Mau*_*olo 69 python multithreading global-variables
如何与线程共享全局变量?
我的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()
Run Code Online (Sandbox Code Playgroud)
我不知道如何让两个线程共享一个变量.
che*_*ner 80
您只需要声明a
为全局输入thread2
,这样您就不会修改a
该函数的本地属性.
def thread2(threadname):
global a
while True:
a += 1
time.sleep(1)
Run Code Online (Sandbox Code Playgroud)
在thread1
,你不需要做任何特殊的事情,只要你不试图修改a
(它会创建一个影响全局变量的局部变量; global a
如果需要,可以使用)>
def thread1(threadname):
#global a # Optional if you treat a as read-only
while a < 10:
print a
Run Code Online (Sandbox Code Playgroud)
val*_*val 45
在一个功能:
a += 1
Run Code Online (Sandbox Code Playgroud)
将被编译器解释为assign to a => Create local variable a
,这不是你想要的.a not initialized
由于(本地)a确实没有被初始化,它可能会因错误而失败:
>>> 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
Run Code Online (Sandbox Code Playgroud)
你可能会得到你想要的东西(非常皱眉,有充分理由)global
关键字,如下:
>>> def f():
... global a
... a += 1
...
>>> a
1
>>> f()
>>> a
2
Run Code Online (Sandbox Code Playgroud)
但是,一般情况下,您应该避免使用极其快速失控的全局变量.对于多线程程序尤其如此,在这些程序中,您没有任何同步机制可以让您thread1
知道何时a
进行了修改.简而言之:线程很复杂,当两个(或多个)线程处理相同的值时,您不能期望直观地了解事件发生的顺序.语言,编译器,操作系统,处理器......都可以发挥作用,并决定为了速度,实用性或任何其他原因修改操作的顺序.
这种事情的正确方法是使用Python共享工具(锁 和朋友),或者更好,通过队列传递数据而不是共享它,例如:
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()
Run Code Online (Sandbox Code Playgroud)
应考虑使用锁,例如threading.Lock
. 有关更多信息,请参阅锁定对象。
接受的答案 CAN print 10 by thread1,这不是您想要的。您可以运行以下代码以更轻松地了解该错误。
def thread1(threadname):
while True:
if a % 2 and not a % 2:
print "unreachable."
def thread2(threadname):
global a
while True:
a += 1
Run Code Online (Sandbox Code Playgroud)
使用锁可以禁止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()
Run Code Online (Sandbox Code Playgroud)
如果线程长时间使用该变量,首先将其处理为局部变量是一个不错的选择。
非常感谢 Jason Pan 提出这个方法。thread1 if 语句不是原子的,因此当该语句执行时,thread2 可能会侵入 thread1,从而允许访问不可访问的代码。我已将之前帖子中的想法组织成一个完整的演示程序(如下),并使用 Python 2.7 运行该程序。
通过一些深思熟虑的分析,我确信我们可以获得进一步的见解,但现在我认为重要的是演示当非原子行为遇到线程时会发生什么。
# ThreadTest01.py - Demonstrates that if non-atomic actions on
# global variables are protected, task can intrude on each other.
from threading import Thread
import time
# global variable
a = 0; NN = 100
def thread1(threadname):
while True:
if a % 2 and not a % 2:
print("unreachable.")
# end of thread1
def thread2(threadname):
global a
for _ in range(NN):
a += 1
time.sleep(0.1)
# end of thread2
thread1 = Thread(target=thread1, args=("Thread1",))
thread2 = Thread(target=thread2, args=("Thread2",))
thread1.start()
thread2.start()
thread2.join()
# end of ThreadTest01.py
Run Code Online (Sandbox Code Playgroud)
正如预测的那样,在运行该示例时,有时实际上会到达“无法访问”的代码,并产生输出。
补充一下,当我在 thread1 中插入一个锁获取/释放对时,我发现打印“无法访问”消息的概率大大降低了。为了查看该消息,我将睡眠时间减少到 0.01 秒,并将 NN 增加到 1000。
对于线程 1 中的锁获取/释放对,我根本没想到会看到该消息,但它就在那里。当我将锁获取/释放对也插入到 thread2 中后,该消息不再出现。在后签名中,thread2 中的增量语句可能也是非原子的。
归档时间: |
|
查看次数: |
132630 次 |
最近记录: |