Python线程锁在简单示例中无效
我好像漏掉了什么,这个简单的例子中有两个线程试图在一个函数里修改一个全局变量,但结果却和预期的不一样:
from threading import Thread, Lock
some_var = 0
def some_func(id):
lo = Lock()
with lo:
global some_var
print("{} here!".format(id))
for i in range(1000000):
some_var += 1
print("{} leaving!".format(id))
t1 = Thread(target=some_func, args=(1,))
t2 = Thread(target=some_func, args=(2,))
t1.start()
t2.start()
t1.join()
t2.join()
print(some_var)
输出结果:
1 here!
2 here!
2 leaving!
1 leaving!
1352010
你可以看到,两个线程同时进入了应该被锁住的部分,导致全局变量'some_var'的增加出现了混乱。
看起来这个锁根本没有起作用,不知道是什么原因。对于范围在10000以内的情况是有效的,但这可能只是因为在这么短的计算时间内,GIL(全局解释器锁)没有被释放。
到底发生了什么呢?
我使用的是Python3.3.2 64位版本。
3 个回答
3
你也可以在你的主函数(main())里定义一个锁,然后把这个锁传递给被调用的函数。
lock = threading.Lock()
t1 = Thread(target=some_func, args=(1,lock))
t2 = Thread(target=some_func, args=(2,lock))
t1.start()
t2.start()
这样的话就只有一个锁了。尽量避免使用全局变量是比较好的做法。
5
每次你的函数被调用时,都会创建一个新的锁,这样每个线程就会有不同的锁。为了让每个线程都能知道同一个锁是否被其他线程占用,锁的对象应该在全局范围内创建。试着把你的锁对象创建成一个全局锁吧!
14
Lock()
这个函数会创建一个全新的锁,只有调用这个函数的线程才能使用这个锁。这就是它为什么不起作用的原因,因为每个线程都在锁住一个完全不同的锁。
锁的对象是少数几个可以安全声明为全局的东西之一,因为你肯定希望每个线程都能看到同一个Lock()
。你应该尝试这样做:
from threading import Thread, Lock
some_var = 0
lo = Lock()
def some_func(id):
global lo
with lo:
global some_var
print("{} here!".format(id))
for i in range(1000000):
some_var += 1
print("{} leaving!".format(id))