锁需要声明为全局变量吗?

3

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

锁是否也必须是全局的?如果不是,那么作为本地变量的锁如何不会导致错误?

谢谢。


你在尝试时遇到了错误吗? - user707650
附注:不要手动调用“acquire”和“release”。尽可能使用“with”语句;它是异常安全的,并避免了忘记正确匹配“acquire”和“release”调用的可能性。 - ShadowRanger
2个回答

2
直接回答问题,counter 需要声明为 global,而 lock 不需要的原因是你正在对 counter 重新赋值(使用 counter += 1),而你只是调用了 lock 的方法。对于变量的引用,如果没有局部变量存在,则 Python 会查看封闭作用域直到找到匹配项。在这种情况下,它在全局作用域中找到了它。对于变量的赋值,在未经声明的情况下 Python 将假定该变量为局部变量(使用 globalnonlocal 进行显式声明)。

1
锁保护某些资源,通常与资源范围相同。在您的情况下,您正在保护全局计数器,因此锁也必须是全局的。访问该资源的所有线程都必须使用相同的锁,因此在函数本身中创建私有锁没有任何好处-其他线程不会看到它。
一些应用程序使用单个锁来保护所有共享资源(粗粒度锁定)。但是,您还可以将锁与数据一起保留(细粒度锁定)。细粒度锁定的示例为:
class MyCounter:

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

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

现在,每个MyCounter实例都有一个锁,并且独立运行。

这看起来不像 Python 风格的。 - df86
什么看起来不像Python?在你的例子中,lock应该像你写的那样是全局的,因为你要保护的资源是全局的。所有使用该资源的代码都需要获取1个锁才能正常工作。 - tdelaney
如果需要的话,您也可以在函数中声明 global lock 并在本地命名空间中保存额外的查找。但通常情况下,如果您不重新绑定变量,则不需要使用 global 关键字。 - tdelaney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接