2016-11-30 116 views
1

Python 3.x都有锁是否需要声明为全局?

import threading 

lock = threading.Lock() 
counter = 0 

def update_counter(): 
    global counter 

    lock.acquire() 
    counter += 1 
    lock.release() 

# starts threads, target update_counter 

是否锁必须是全球性的?如果不是,由于未定义本地锁定,它不会导致错误?

谢谢

+0

试用时是否遇到错误? – Evert

+0

附注:不要手动调用'acquire'和'release'。尽可能使用'with'语句;它是例外的安全的,并且避免了忘记正确匹配'acquire'和'release'的可能性。 – ShadowRanger

回答

1

直接回答这个问题,那counter需要声明globallock不会是因为你重新分配到counter(与counter += 1)的原因,而你只在lock调用方法。对于一个变量的引用,如果没有局部变量存在,Python会查找封闭范围直到它找到一个匹配。在这种情况下,它会在全局范围内找到它。对于变量的赋值,Python将假定该变量是本地的,除非另有明确声明(使用globalnonlocal)。

0

锁保护一些资源,并且通常与资源的范围相同。在你的情况下,你正在保护一个全局计数器,所以锁定也必须是全局的。所有访问资源的线程都必须使用相同的锁,因此在函数本身中创建私有锁是没有用的 - 没有其他线程会看到它。

某些应用程序使用单个锁来保护所有共享资源(粒度锁定)。但是你也可以锁定数据(细粒度锁定)。细粒度锁定的一个实例是:

class MyCounter: 

    def __init__(self): 
     self.lock = threading.Lock() 
     self.value = 0 

    def increment(self): 
     with self.lock: 
      self.value += 1 

现在,MyCounter每个实例具有锁定和独立运行。

+0

似乎并不pythonic – df86

+0

什么似乎pythonic?在你的例子中,'lock'应该是全局的,就像你写的那样,因为你所保护的资源是全局的。所有使用该资源的代码都需要获取1个锁才能工作。 – tdelaney

+0

您也可以在函数中声明'全局锁定'并在本地命名空间中保存额外的查找。但一般来说,如果您不重新绑定变量,则不需要'global'关键字。 – tdelaney