python - Python中的线程本地存储

标签 python multithreading thread-local-storage

如何在 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() 对象只需要创建一次,而不是每个线程一次,也不是每个函数调用一次。 globalclass 级别是理想的位置。

原因如下:threading.local() 实际上在每次调用时都会创建一个新实例(就像任何工厂或类调用一样),所以调用 threading.local() 多次不断地覆盖原始对象,这很可能不是人们想要的。当任何线程访问现有的 threadLocal 变量(或任何它被调用的)时,它都会获得该变量的私有(private) View 。

这不会按预期工作:

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 和每个线程的计数和顺序会因运行而异。

关于python - Python中的线程本地存储,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1408171/

相关文章:

java - 如果我们可以使用普通线程,为什么还要使用守护线程。守护线程可以做但普通线程不能做的事情是什么

multithreading - 为什么使用线程局部存储(TlsAlloc、TlsGetValue、ets)而不是局部变量

python - Pandas Groupby EWM

python - 是否有用于 python 的已建立的 memoize 磁盘装饰器?

Android - 线程正在破坏应用程序

multithreading - IIS 工作线程问题

c - 有没有办法在线程创建/销毁时调用库线程局部初始化/清理?

c# - `AsyncLocal` 是否也做 `ThreadLocal` 做的事情?

python - 在 django admin 中使用时与图像字段相关的问题

python - python图像处理中如何做OR掩码操作?