Skip to main content
 首页 » 编程设计

python之python threading.Lock() 是否锁定所有需要锁定的东西

2025年05月04日28kenshinobiy

下面的脚本是抽象的。我的问题是关于 threading.Lock()

的使用

锁定限制了对“共享资源”的访问,但我对这能走多远感到紧张。在本示例中,我有对象属性,它们是具有数组属性的对象列表。在某些情况下,依赖关系会更远。

Lock() 是否确实“知道”所有需要锁定的东西?

还显示了以下脚本的输出。该脚本的目的主要是为了讨论 - 它不会失败,但我不确定它是否锁定了所需的一切。

start:   [array([0, 1]), array([0, 1, 2]), array([0, 1, 2, 3])] 
append an object 
done! 
finish:  [array([505, 605]), array([10, 11, 12]), array([10, 11, 12, 13]), array([5])] 
 
 
import time 
from threading import Thread, Lock 
import numpy as np 
 
class Bucket(object): 
    def __init__(self, objects): 
        self.objects = objects 
 
class Object(object): 
    def __init__(self, array): 
        self.array = array 
 
class A(Thread): 
    def __init__(self, bucket): 
        Thread.__init__(self) 
        self.bucket      = bucket 
    def run(self): 
        nloop            = 0 
        locker           = Lock() 
        n = 0 
        while n < 10: 
            with locker:   
                objects = self.bucket.objects[:]  # makes a local copy of list each time 
            for i, obj in enumerate(objects): 
                with locker: 
                    obj.array += 1 
                time.sleep(0.2) 
            n += 1 
            print 'n: ', n 
        print "done!" 
        return 
 
objects = [] 
for i in range(3): 
    ob = Object(np.arange(i+2)) 
    objects.append(ob) 
bucket = Bucket(objects) 
 
locker           = Lock() 
 
a = A(bucket) 
print [o.array for o in bucket.objects] 
 
a.start() 
 
time.sleep(3) 
 
with locker: 
    bucket.objects.append(Object(np.arange(1)))  # abuse the bucket! 
    print 'append an object' 
time.sleep(5) 
 
print [o.array for o in bucket.objects] 

请您参考如下方法:

你似乎误解了锁的工作原理。

锁不锁定任何对象,它只能锁定线程执行。

尝试进入 with locker: block 的第一个线程成功。

如果另一个线程试图进入一个 with locker: block (具有相同的 locker 对象),它会被延迟,直到第一个线程退出 block ,所以两个线程都不能同时更改 block 内变量的值。

这里您的“共享资源”是您在 block 中更改的变量:如我所见,objects 和 obj.array。您基本上是在保护它们免受并发访问(也就是说 - 在没有 GIL 的 python 版本中)只是因为一次只有一个线程可以更改它们

老前辈称其为临界区,其中一次只能执行 1 个线程。

请注意,对不同的资源使用相同的 locker 对象有点可疑。这有更多的机会死锁/比它需要的更慢。

(如果你嵌套 2 个 with locker 调用你会遇到死锁 - 如果你想这样做,你需要一个 RLock)

就是这么简单。