使用线程与全局变量

2024-04-27 21:20:14 发布

您现在位置:Python中文网/ 问答频道 /正文

如何与线程共享全局变量?

我的Python代码示例是:

from threading import Thread
import time
a = 0  #global variable

def thread1(threadname):
    #read variable "a" modify by thread 2

def thread2(threadname):
    while 1:
        a += 1
        time.sleep(1)

thread1 = Thread( target=thread1, args=("Thread-1", ) )
thread2 = Thread( target=thread2, args=("Thread-2", ) )

thread1.join()
thread2.join()

我不知道如何让两个线程共享一个变量。


Tags: 代码import示例targettimedefargs线程
3条回答

应该考虑使用锁,例如threading.Lock。有关详细信息,请参见lock-objects

接受的答案可以按thread1打印10,这不是您想要的。您可以运行以下代码来更容易地理解错误。

def thread1(threadname):
    while True:
      if a % 2 and not a % 2:
          print "unreachable."

def thread2(threadname):
    global a
    while True:
        a += 1

使用锁可以禁止在多次读取时更改a

def thread1(threadname):
    while True:
      lock_a.acquire()
      if a % 2 and not a % 2:
          print "unreachable."
      lock_a.release()

def thread2(threadname):
    global a
    while True:
        lock_a.acquire()
        a += 1
        lock_a.release()

如果线程长时间使用该变量,则最好先将其转换为局部变量。

在函数中:

a += 1

将被编译器解释为assign to a => Create local variable a,这不是您想要的。由于(本地)a确实尚未初始化,它可能会失败,并出现a not initialized错误:

>>> a = 1
>>> def f():
...     a += 1
... 
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f
UnboundLocalError: local variable 'a' referenced before assignment

你可能会得到你想要的(非常不赞成,而且理由充分)global关键字,比如:

>>> def f():
...     global a
...     a += 1
... 
>>> a
1
>>> f()
>>> a
2

但是,一般来说,应该避免使用全局变量,因为全局变量很快就会失控。对于多线程程序来说尤其如此,在多线程程序中,没有任何同步机制可以让您的thread1知道a何时被修改。简而言之:线程是复杂的,当两个(或更多)线程处理同一个值时,您不能期望直观地了解事件发生的顺序。语言,编译器,操作系统,处理器。。。都能起到作用,并决定为了速度、实用性或任何其他原因修改操作顺序。

这类事情的正确方法是使用Python共享工具(locks) 或者更好,通过Queue而不是共享数据,例如:

from threading import Thread
from queue import Queue
import time

def thread1(threadname, q):
    #read variable "a" modify by thread 2
    while True:
        a = q.get()
        if a is None: return # Poison pill
        print a

def thread2(threadname, q):
    a = 0
    for _ in xrange(10):
        a += 1
        q.put(a)
        time.sleep(1)
    q.put(None) # Poison pill

queue = Queue()
thread1 = Thread( target=thread1, args=("Thread-1", queue) )
thread2 = Thread( target=thread2, args=("Thread-2", queue) )

thread1.start()
thread2.start()
thread1.join()
thread2.join()

只需在thread2中将a声明为全局,这样就不会修改该函数的本地a

def thread2(threadname):
    global a
    while True:
        a += 1
        time.sleep(1)

thread1中,只要不尝试修改a(这将创建一个隐藏全局变量的局部变量;如果需要,请使用global a)的值,就不需要做任何特殊的事情

def thread1(threadname):
    #global a       # Optional if you treat a as read-only
    while a < 10:
        print a

相关问题 更多 >