实例变量的线程问题

时间:2011-08-13 01:49:00

标签: python multithreading thread-safety python-3.x

所以我似乎误解了一些关于Python的基本内容。将实例变量传递给函数应该只传递对象本身的引用,所以如果对象是不可变的,那么像self.var = "something"; foo(self.var)这样的东西不应该改变self.var如果foo为变量赋予了一个新值 - 所以一切都很好,正如预期的那样。

但现在考虑一下:

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-5的打印顺序做出任何假设,但我认为每个arg应该只打印一次。但我得到以下输出(Win7 x64,python 3.1 x64)

Bar: arg0
Bar: arg2
Bar: arg2
Bar: arg5
Bar: arg3

编辑:好的,在输入之后,我有一个光荣的想法,可能在创建线程时可能没有执行lambda表达式,但稍后会解释行为,因此简单的解决方法是创建一个本地变量并使用它。好吧 - 现在这是SO的快速帮助;)

1 个答案:

答案 0 :(得分:2)

因为我注意到我还没有回答那个,所以我们走了:

lambda为self而不是self.arg本身创建一个闭包,这意味着当我们稍后执行bar时,我们访问最新值而不是lambda创建时的值。