何时以及如何使用Python的RLock [英] When and how to use Python's RLock

查看:145
本文介绍了何时以及如何使用Python的RLock的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在阅读Python文档时,我遇到了RLock.

有人可以举例说明一种情况吗,其中 RLock 优于 Lock ?

特别参考:

  • RLock的递归级别".这有什么用?
  • RLock对象的线程所有权"
  • 性能?

解决方案

这是我看到用法的一个示例:

在以下时间有用

  1. 您想从类外部进行线程安全访问,并从类内部使用相同的方法:

    class X:
        def __init__(self):
            self.a = 1
            self.b = 2
            self.lock = threading.RLock()
    
        def changeA(self):
            with self.lock:
                self.a = self.a + 1
    
        def changeB(self):
            with self.lock:
                self.b = self.b + self.a
    
        def changeAandB(self):
            # you can use chanceA and changeB thread-safe!
            with self.lock:
                self.changeA() # a usual lock would block at here
                self.changeB()
    

  2. 对于递归更为明显:

    lock = threading.RLock()
    def a(...):
         with lock:
    
             a(...) # somewhere inside
    

    其他线程必须等到第一次调用a完成=线程所有权.

性能

通常,我开始使用Lock进行编程,当发生情况1或2时,我切换到RLock. 直到Python 3.2 ,RLock应该会慢一些由于附加的代码.它使用Lock:

Lock = _allocate_lock # line 98 threading.py

def RLock(*args, **kwargs):
    return _RLock(*args, **kwargs)

class _RLock(_Verbose):

    def __init__(self, verbose=None):
        _Verbose.__init__(self, verbose)
        self.__block = _allocate_lock()

线程所有权

在给定线程中,您可以根据需要经常获取RLock.其他线程需要等待,直到该线程再次释放资源.

这与Lock不同,后者暗示函数调用所有权"(我这样称呼):另一个函数调用必须等待,直到最后一个阻塞函数释放了该资源,即使该资源位于即使其他函数调用了相同的线程,也是如此.

何时使用Lock代替RLock

当您无法控制的资源外部呼叫时.

下面的代码具有两个变量:a和b,并且应使用RLock来确保a == b * 2

import threading
a = 0 
b = 0
lock = threading.RLock()
def changeAandB(): 
    # this function works with an RLock and Lock
    with lock:
        global a, b
        a += 1
        b += 2
        return a, b

def changeAandB2(callback):
    # this function can return wrong results with RLock and can block with Lock
    with lock:
        global a, b
        a += 1
        callback() # this callback gets a wrong value when calling changeAandB2
        b += 2
        return a, b

changeAandB2中,锁定确实会阻止,但它是正确的选择.或者可以使用RLock._is_owned()进行错误增强.当您实现了观察者模式或发布者-订阅者并在之后添加锁定后,可能会发生诸如changeAandB2之类的功能.

Reading through the Python docs I came across RLock.

Can someone explain to me (with example) a scenario in which RLock would be preferred to Lock?

With particular reference to:

  • RLock's "recursion level". How is this useful?
  • A threads "ownership" of an RLock object
  • Performance?

解决方案

This is one example where I see the use:

Useful when

  1. you want to have thread-safe access from outside the class and use the same methods from inside the class:

    class X:
        def __init__(self):
            self.a = 1
            self.b = 2
            self.lock = threading.RLock()
    
        def changeA(self):
            with self.lock:
                self.a = self.a + 1
    
        def changeB(self):
            with self.lock:
                self.b = self.b + self.a
    
        def changeAandB(self):
            # you can use chanceA and changeB thread-safe!
            with self.lock:
                self.changeA() # a usual lock would block at here
                self.changeB()
    

  2. for recursion more obvious:

    lock = threading.RLock()
    def a(...):
         with lock:
    
             a(...) # somewhere inside
    

    other threads have to wait until the first call of a finishes = thread ownership.

Performance

Usually, I start programming with the Lock and when case 1 or 2 occur, I switch to an RLock. Until Python 3.2 the RLock should be a bit slower because of the additional code. It uses Lock:

Lock = _allocate_lock # line 98 threading.py

def RLock(*args, **kwargs):
    return _RLock(*args, **kwargs)

class _RLock(_Verbose):

    def __init__(self, verbose=None):
        _Verbose.__init__(self, verbose)
        self.__block = _allocate_lock()

Thread Ownership

within the given thread you can acquire a RLock as often as you like. Other threads need to wait until this thread releases the resource again.

This is different to the Lock which implies 'function-call ownership'(I would call it this way): Another function call has to wait until the resource is released by the last blocking function even if it is in the same thread = even if it is called by the other function.

When to use Lock instead of RLock

When you make a call to the outside of the resource which you can not control.

The code below has two variables: a and b and the RLock shall be used to make sure a == b * 2

import threading
a = 0 
b = 0
lock = threading.RLock()
def changeAandB(): 
    # this function works with an RLock and Lock
    with lock:
        global a, b
        a += 1
        b += 2
        return a, b

def changeAandB2(callback):
    # this function can return wrong results with RLock and can block with Lock
    with lock:
        global a, b
        a += 1
        callback() # this callback gets a wrong value when calling changeAandB2
        b += 2
        return a, b

In changeAandB2 the Lock would be the right choice although it does block. Or one can enhance it with errors using RLock._is_owned(). Functions like changeAandB2 may occur when you have implemented an Observer pattern or a Publisher-Subscriber and add locking afterward.

这篇关于何时以及如何使用Python的RLock的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆