实例变量的线程问题
看起来我对Python的一些基本概念有点误解。把一个实例变量传给一个函数,应该只是传递这个对象的引用,也就是说,如果这个对象是不可变的,像这样做 self.var = "something"; foo(self.var)
不应该改变self.var的值,只要一切正常。
但是现在考虑这个情况:
import threading
class Test():
def __init__(self):
self.lock = threading.Lock()
self.arg = "arg0"
def foo(self, i):
with self.lock:
threading.Thread(target=lambda: bar(self.arg)).start()
self.arg = "arg" + str(i)
def bar(arg):
import time
time.sleep(1)
print("Bar: " + arg)
if __name__ == '__main__':
t = Test()
for i in range(1, 6):
t.foo(i)
我创建了一个线程对象,并且给它传递了当前字符串的引用,然后我更新了这个字符串——而这个线程不应该看到这个更新。由于有锁的存在,下一条线程也应该在更新之后才开始运行——所以虽然我不能确定arg0到arg5的打印顺序,但我认为每个arg应该只打印一次。但是我得到了以下输出(Win7 x64,python 3.1 x64)
Bar: arg0
Bar: arg2
Bar: arg2
Bar: arg5
Bar: arg3
编辑:好吧,写完这些后,我突然想到,可能lambda表达式并不是在创建线程时执行的,而是在之后执行的,这就解释了这个行为。所以简单的解决办法就是创建一个局部变量并使用它。嗯——这真是得到了快速的帮助,感谢SO ;)
1 个回答
2
我发现我还没有回答这个问题,所以现在来解释一下:
这个 lambda 表达式会创建一个对 self
的闭包,但并不是对 self.arg
本身的闭包。这意味着当我们稍后执行 bar 时,我们访问的是最新的值,而不是 lambda 创建时的那个值。