什么是Python中的“线程本地存储”,为什么我需要它?

特别是在Python中,variables如何在线程之间共享?

虽然我已经使用threading.Thread之前,我从来没有真正理解或看到如何variables共享的例子。 他们在主线和孩子之间还是在孩子之间共享? 我什么时候需要使用线程本地存储来避免这种共享?

我已经看到许多关于使用锁来同步对线程之间的共享数据的访问的警告,但是我还没有看到这个问题的一个很好的例子。

提前致谢!

在Python中,除了函数局部variables之外,所有东西都是共享的(因为每个函数调用都有它自己的本地集合,线程总是独立的函数调用)。即使如此,只有variables本身(引用对象的名称)是本地的function; 对象本身总是全局的,任何东西都可以引用它们。 特定线程的Thread对象在这方面不是一个特殊的对象。 如果将Thread对象存储在所有线程都可以访问的地方(如全局variables),则所有线程都可以访问该Thread对象。 如果你想以primefaces方式修改你不是在同一个线程中创build的任何东西 ,也不会在其他任何线程存储的地方存储,则必须通过锁来保护它。 而所有的线程当然必须共享这个相同的锁,否则它不会很有效。

如果你想要真正的线程本地存储,这就是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()。开始()
我被称为线程2
我从线程1调用 

这里threading.local()被用来作为一个快速和肮脏的方式来传递一些数据从run()到bar()而不改变foo()的接口。

请注意,使用全局variables不会有诀窍:

 #/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()。开始()
我被称为线程2
我被称为线程2 

同时,如果你能够承担通过foo()这个parameter passing这个数据 – 这将是一个更加优雅和精心devise的方式:

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

但是,使用第三方或devise不佳的代码时,这并不总是可行的。

您可以使用threading.local()创build线程本地存储。

 >>> tls = threading.local() >>> tls.x = 4 >>> tls.x 4 

存储到tls的数据对每个线程都是唯一的,这将有助于确保不会发生无意的共享。

就像其他语言一样,Python中的每个线程都可以访问相同的variables。 “主线程”和子线程之间没有区别。

与Python的一个区别是全局解释器锁意味着一次只有一个线程可以运行Python代码。 这对于同步访问没有多大帮助,但是,由于所有通常的先发制人问题仍然适用,您必须像使用其他语言一样使用线程原语。 这意味着如果您使用线程来执行性能,则需要重新考虑。