如何在Python中使用线程本地存储?
例如,如果您有一个线程工作池,并且每个线程都需要访问其自己的资源(例如网络或数据库连接),则线程本地存储很有用。请注意,该threading
模块使用常规的线程概念(可以访问进程全局数据),但是由于全局解释器锁定,它们并不是太有用。不同的multiprocessing
模块会为每个模块创建一个新的子流程,因此任何全局变量都将是线程局部的。
这是一个简单的示例:
import threading
from threading import current_thread
threadLocal = threading.local()
def hi():
initialized = getattr(threadLocal, 'initialized', None)
if initialized is None:
print("Nice to meet you", current_thread().name)
threadLocal.initialized = True
else:
print("Welcome back", current_thread().name)
hi(); hi()
这将打印出:
Nice to meet you MainThread
Welcome back MainThread
一件很容易被忽略的重要事情:一个threading.local()
对象只需要创建一次,而不是每个线程一次或每个函数调用一次。的global
或class
水平的理想地点。
这就是为什么:threading.local()
每次调用它时都会实际上创建一个新实例(就像任何工厂或类调用一样),因此threading.local()
多次调用会不断覆盖原始对象,这很可能不是您想要的。当任何线程访问现有threadLocal
变量(或任何被调用的变量)时,它将获得该变量的私有视图。
这将无法正常工作:
import threading
from threading import current_thread
def wont_work():
threadLocal = threading.local() #oops, this creates a new dict each time!
initialized = getattr(threadLocal, 'initialized', None)
if initialized is None:
print("First time for", current_thread().name)
threadLocal.initialized = True
else:
print("Welcome back", current_thread().name)
wont_work(); wont_work()
将产生以下输出:
First time for MainThread
First time for MainThread
因为multiprocessing
模块为每个线程创建一个新进程,所以所有全局变量都是线程局部的。
考虑以下示例,其中processed
计数器是线程本地存储的示例:
from multiprocessing import Pool
from random import random
from time import sleep
import os
processed=0
def f(x):
sleep(random())
global processed
processed += 1
print("Processed by %s: %s" % (os.getpid(), processed))
return x*x
if __name__ == '__main__':
pool = Pool(processes=4)
print(pool.map(f, range(10)))
它将输出如下内容:
Processed by 7636: 1
Processed by 9144: 1
Processed by 5252: 1
Processed by 7636: 2
Processed by 6248: 1
Processed by 5252: 2
Processed by 6248: 2
Processed by 9144: 2
Processed by 7636: 3
Processed by 5252: 3
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
…当然,线程ID以及每个线程ID和每个命令的计数会因运行而异。
线程本地存储指针允许开发者存储值到任务的控制块(control block)中,使这个值对于任务来说是特定且唯一的。 线程本地存储经常被用来存储数据,而单一进程的应用程序通常的做法是使用全局变量。比如,很多库函数包含一个全局的返回值--错误信息,应用根据这个错误信息判读错误类型,同时进行相应处理。在单线程的应用中可以使用全局变量来保存这个错误信息,但是在多任务的系统中,每个任务都必须有一个自己的位
抱歉,目前我还没有完成这个主题,请稍后再来。 如果你对这一主题感兴趣,可以参考本站的: C++小品:井水不犯河水的thread_specific_ptr,C++11线程库中的本地存储 C++小品:井水不犯河水在PPL中的实现:combinable以及task_group,task 参考: [N2659 = 08-0169] Lawrence Crowl: Thread-Local Storage
问题内容: 实际上如何解决“ foo”?编译器是否以函数调用静默替换“ foo”的每个实例?“ foo”是否存储在相对于堆栈底部的某个位置,并且编译器将其存储为“嘿,对于每个线程,此空间都位于堆栈底部附近,而foo存储为’距堆栈底部的偏移量x”。 “? 问题答案: 这有点复杂(本文档对此进行了详细说明),但实际上两者都不是。而是,编译器在可执行文件中放置一个特殊的.tdata节,其中包含所有线程局
问题内容: 特别是在Python中,如何在线程之间共享变量? 尽管我以前从未使用过,但从未真正理解或看到过如何共享变量的示例。它们是在主线程和子线程之间共享还是仅在子线程之间共享?我何时需要使用线程本地存储来避免这种共享? 我已经看到许多有关通过使用锁在线程之间同步对共享数据的访问的警告,但是我还没有看到这个问题的一个很好的例子。 提前致谢! 问题答案: 在Python中,所有内容都是共享的,但函
问题内容: 在多个帖子中都提到了这一点:不当使用会导致内存泄漏。我正在努力了解使用内存泄漏将如何发生。 我发现的唯一情况如下: Web服务器维护一个线程池(例如,用于servlet)。如果未删除其中的变量,则这些线程可能会导致内存泄漏,因为线程不会死亡。 这种情况下没有提到“ Perm Space”内存泄漏。那是内存泄漏的唯一(主要)用例吗? 问题答案: PermGen的exhaustions 与
问题内容: 这个问题使我想知道Java和.NET等高级开发框架中的线程本地存储。 Java有一个类(也许还有其他结构),而.NET有数据插槽,很快就有了自己的类。(它也具有,但我对成员数据的线程本地存储特别感兴趣。)大多数其他现代开发环境都在语言或框架级别为其提供了一种或多种机制。 线程本地存储解决了哪些问题,或者与创建独立对象实例以包含线程本地数据的标准的面向对象的习语相比,线程本地存储提供了哪