我在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/