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

标签 python multithreading immutability

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

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

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

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

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

如果确实存在每个字典锁定,有没有办法避免它?

最佳答案

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

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

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

关于python - 在Python中的线程之间共享字典时是否可以避免锁定开销?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32657840/

相关文章:

python - 创建循环赛,替代解决方案?

python - 运行外部子进程并读取返回码

java - 如何使示例 MulticastChat 运行?

java - 当实例变量以 arraylist 形式存在时类的不变性

python - 是否可以在 PyScript 中使用 OpenCV 模块?

python - 希望在 python 中解析字符串

c# - List.AsParallel() - 如何命名我的线程?

c++ - C++中的高速缓冲

c# - 重载 '+' 的不可变列表是否有意义?

nhibernate - 为什么 NHibernate 删除不可变类实例?