Skip to main content
 首页 » 编程设计

python之在 Python 中的线程之间共享字典时是否可以避免锁定开销

2024年08月25日42myhome

我在 Python 中有一个多线程应用程序,其中线程读取非常大(因此我无法将它们复制到线程本地存储)字典(从磁盘读取并且从未修改过)。然后他们使用字典作为只读数据处理大量数据:

# single threaded 
d1,d2,d3 = read_dictionaries() 
while line in stdin: 
    stdout.write(compute(line,d1,d2,d3)+line) 

我试图通过使用线程来加快速度,然后每个线程都会读取自己的输入并写入自己的输出,但由于字典很大,我希望线程共享存储空间。

IIUC,每次线程从 dict 读取时,它都必须锁定它,这会给应用程序带来性能成本。这种数据锁定是不必要的,因为字典是只读的。

CPython 实际上是单独锁定数据还是只是使用 GIL ?

如果确实存在 per-dict 锁定,是否有办法避免它?

请您参考如下方法:

python中的多线程处理是没用的。最好使用多处理模块。因为多线程只能在较少的情况下做出积极的努力。

Python implementation detail: In CPython, due to the Global Interpreter Lock, only one thread can execute Python code at once (even though certain performance-oriented libraries might overcome this limitation). If you want your application to make better use of the computational resources of multi-core machines, you are advised to use multiprocessing. However, threading is still an appropriate model if you want to run multiple I/O-bound tasks simultaneously. Official documentation.

没有您身边的任何代码示例,我只能建议将您的大词典分成几个部分,并使用 Pool.map 处理每个部分。 .并在主进程中合并结果。

不幸的是,不可能有效地在不同的 python 进程之间共享大量内存(我们不是在谈论基于 mmap 的共享内存模式)。但是您可以在不同的过程中阅读字典的不同部分。或者只是在主进程中读取整个字典并给子进程一小部分。

另外,我应该警告你,你应该非常小心地使用多处理算法。因为每增加一兆字节,进程数就会成倍增加。

因此,根据您的伪代码示例,我可以基于compute 函数假设两种可能的算法:

# "Stateless" 
for line in stdin: 
    res = compute_1(line) + compute_2(line) + compute_3(line) 
    print res, line 
 
# "Shared" state 
for line in stdin: 
    res = compute_1(line) 
    res = compute_2(line, res) 
    res = compute_3(line, res) 
    print res, line 

在第一种情况下,您可以创建多个 worker,根据 Process class 在单独的 worker 中读取每个字典。 (减少每个进程的内存使用量是个好主意),并像生产线一样计算它。

在第二种情况下,您有一个共享状态。对于下一个 worker ,您需要上一个 worker 的结果。这是多线程/多处理编程的最坏情况。但是您可以在那里编写算法,几个工作人员正在使用相同的队列并将结果推送到它而无需等待所有周期完成。而你只是分享一个Queue进程之间的实例。