我有一个更新全局/类变量的函数。 那么,经常调用subthread等函数后应该注意什么?(以异步方式)
或者,有什么建议可以避免使用这种模式? (病态的方式)
import time
import threading
# through global variable or class variable
_a = 123
def update_a(): # may be called more than once
"slow updating process"
time.sleep(3)
global _a
_a += 10
return
if __name__ == '__main__':
print(_a)
th = threading.Thread(target=update_a)
th.setDaemon(True)
th.start()
print(_a)
# updating aynchrounously
time.sleep(5)
print(_a)
答案 0 :(得分:0)
这表明addition is not threadsafe(请参阅Josiah Carlson的评论。effbot.org
现在似乎已经关闭;您可以通过wayback machine here查看页面的存档版本。):
import threading
x = 0
def foo():
global x
for i in xrange(1000000):
x += 1
threads = [threading.Thread(target=foo), threading.Thread(target=foo)]
for t in threads:
t.daemon = True
t.start()
for t in threads:
t.join()
print(x)
产生一些小于2000000的数字。这表明对x += 1
的一些调用未正确更新变量。
解决方案是使用锁保护对全局变量的赋值:
lock = threading.Lock()
def safe_foo():
global x
for i in xrange(1000000):
with lock:
x += 1
x = 0
threads = [threading.Thread(target=safe_foo), threading.Thread(target=safe_foo)]
for t in threads:
t.daemon = True
t.start()
for t in threads:
t.join()
print(x)
产生2000000。
答案 1 :(得分:0)
首先,在Python中完全避免使用线程,但如果你真的想要,我会这样做。首先,使用lock:
创建一个线程安全的对象class ThreadSafeValue(object):
def __init__(self, init):
self._value = init
self._lock = threading.Lock()
def atomic_update(self, func):
with self._lock:
self._value = func(self._value)
@property
def value(self):
return self._value
然后我将它传递给线程目标函数:
def update(val):
time.sleep(3)
val.atomic_update(lambda v: v + 10)
def main():
a = ThreadSaveValue(123)
print a.value
th = threading.Thread(target=update, args=(a,))
th.daemon = True
th.start()
print a.value
th.join()
print a.value
if __name__ == '__main__':
main()
这样你就可以避免全局变量并确保线程安全。