如果/我应该使用线程来更新全局变量。[pythonic way]

时间:2013-06-25 14:04:18

标签: python multithreading

我有一个更新全局/类变量的函数。 那么,经常调用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)

2 个答案:

答案 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()

这样你就可以避免全局变量并确保线程安全。