在Python具体如何做的变量得到线程之间共享?
虽然我用threading.Thread
之前,我从来没有真正理解或看到的变量是怎么共享的例子。 他们在主线程和孩子之间或只在孩子们共享? 我什么时候需要使用线程本地存储,以避免这种共享?
我已经看到了有关使用锁的同步访问线程之间共享数据很多警告,但我还没有看到问题的一个很好的例子。
提前致谢!
在Python具体如何做的变量得到线程之间共享?
虽然我用threading.Thread
之前,我从来没有真正理解或看到的变量是怎么共享的例子。 他们在主线程和孩子之间或只在孩子们共享? 我什么时候需要使用线程本地存储,以避免这种共享?
我已经看到了有关使用锁的同步访问线程之间共享数据很多警告,但我还没有看到问题的一个很好的例子。
提前致谢!
在Python中,一切都是共享的,除了功能的局部变量(因为每个函数调用都有自己的一套当地人和线程总是单独的函数调用)。即使如此,只有变量本身(即引用对象的名称)是本地的功能; 对象本身始终是全局的,而且什么都可以参考它们。 该Thread
特定线程对象是不是在这方面的特殊对象。 如果存储Thread
对象的某处所有线程可以访问(比如一个全局变量),那么所有的线程可以访问一个Thread
对象。 如果你想修改原子什么 ,你不只是建立在这个非常相同的线程,并没有任何地方存储另一个线程可以得到它,你必须通过一个锁来保护它。 和所有线程都必须当然共享这同一个锁,或者它不会是非常有效的。
如果你想实际线程本地存储,这就是threading.local
进来的属性。 threading.local
不是线程之间共享; 每个线程只看到它本身放置在那里的属性。 如果你想了解它的实现,源是在_threading_local.py标准库。
考虑下面的代码:
#/usr/bin/env python
from time import sleep
from random import random
from threading import Thread, local
data = local()
def bar():
print("I'm called from", data.v)
def foo():
bar()
class T(Thread):
def run(self):
sleep(random())
data.v = self.getName() # Thread-1 and Thread-2 accordingly
sleep(1)
foo()
>> T().start(); T().start() I'm called from Thread-2 I'm called from Thread-1
这里threading.local()被用作一个快速和肮脏的方式来传递从运行的一些数据()以禁止(),而不改变foo的接口()。
请注意,使用全局变量不会做的伎俩:
#/usr/bin/env python
from time import sleep
from random import random
from threading import Thread
def bar():
global v
print("I'm called from", v)
def foo():
bar()
class T(Thread):
def run(self):
global v
sleep(random())
v = self.getName() # Thread-1 and Thread-2 accordingly
sleep(1)
foo()
>> T().start(); T().start() I'm called from Thread-2 I'm called from Thread-2
同时,如果你有能力通过通过这个数据为Foo()的参数 - 这将是一个更优雅和精心设计的方式:
from threading import Thread
def bar(v):
print("I'm called from", v)
def foo(v):
bar(v)
class T(Thread):
def run(self):
foo(self.getName())
但使用第三方或设计不当的代码时,这是不可能的。
您可以通过创建线程本地存储threading.local()
>>> tls = threading.local()
>>> tls.x = 4
>>> tls.x
4
存储到的TLS数据将是唯一的每个线程,这将有助于确保无意共享不会发生。
就像在所有其他语言,Python中的每一个线程可以访问相同的变量。 还有的“主线程”和子线程之间没有区别。
与Python的一个区别是,全局解释器锁意味着,只有一个线程可以同时运行Python代码。 这是没有太大的帮助,当谈到同步访问,但是,由于所有常见的优先购买权问题仍然适用,你必须使用线程原语就像在其他语言。 它意味着你需要的,如果你正在使用但性能线程,重新考虑。