并行读取大文件?

Anu*_*ush 19 python performance multiprocessing

我有一个大文件,我需要阅读并从中制作字典.我希望这个尽可能快.但是我在python中的代码太慢了.这是一个显示问题的最小示例.

首先制作一些假数据

paste <(seq 20000000) <(seq 2 20000001)  > largefile.txt
Run Code Online (Sandbox Code Playgroud)

现在这里有一段最小的python代码来读取它并制作一本字典.

import sys
from collections import defaultdict
fin = open(sys.argv[1])

dict = defaultdict(list)

for line in fin:
    parts = line.split()
    dict[parts[0]].append(parts[1])
Run Code Online (Sandbox Code Playgroud)

时序:

time ./read.py largefile.txt
real    0m55.746s
Run Code Online (Sandbox Code Playgroud)

但是,可以更快地读取整个文件:

time cut -f1 largefile.txt > /dev/null    
real    0m1.702s
Run Code Online (Sandbox Code Playgroud)

我的CPU有8个内核,是否有可能在python中并行化这个程序来加速它?

一种可能性是读入大块输入,然后在不同的非重叠子块上并行运行8个进程,使字典与内存中的数据并行,然后在另一个大块中读取.在某种程度上使用多处理的python中这是可能的吗?

更新.假数据不是很好,因为每个键只有一个值.更好的是

perl -E 'say int rand 1e7, $", int rand 1e4 for 1 .. 1e7' > largefile.txt
Run Code Online (Sandbox Code Playgroud)

(与大文件中的读取和制作字典相关.)

Use*_*ess 6

可以并行化以加快速度,但是并行进行多次读取不太可能有所帮助。

您的操作系统不太可能有效地并行执行多次读取(例外是类似条带化RAID阵列的情况,在这种情况下,您仍然需要知道跨步才能最佳利用它)。

您可以做的是与读取并行运行相对昂贵的字符串/字典/列表操作。

因此,一个线程读取(大)块并将其推入同步队列,一个或多个使用者线程从队列中拉出块,将其拆分为行,然后填充字典。

(如果您要使用多个使用者线程,如Pappnese所说,请为每个线程构建一个字典,然后将其加入)。


提示:


回覆。赏金:

C显然没有GIL可以与之抗衡,因此多个使用者可能会更好地扩展。读取行为不会改变。不利的一面是C缺乏对哈希映射(假设您仍然想要Python样式的字典)和同步队列的内置支持,因此您必须找到合适的组件或编写自己的组件。多个消费者各自建立自己的字典,然后在最后合并它们的基本策略可能仍然是最好的。

使用strtok_r代替str.split可能会更快,但是请记住,您还需要手动管理所有字符串的内存。哦,您也需要逻辑来管理线段。老实说,C为您提供了许多选择,我认为您只需要对其进行概要分析即可看到。

  • 谢谢。您介意告诉我该怎么做吗? (2认同)

Eci*_*ana 2

几年前,蒂姆·布雷 (Tim Bray) 的网站上有一篇关于此问题的博客文章系列“Wide Finder Project”[1]。您可以在那里找到由 ElementTree [3] 和 PIL [4] 的 Fredrik Lundh 提供的解决方案 [2]。我知道在这个网站上通常不鼓励发布链接,但我认为这些链接比复制粘贴他的代码给你更好的答案。

[1] http://www.tbray.org/ongoing/When/200x/2007/10/30/WF-Results
[2] http://effbot.org/zone/wide-finder.htm
[3] http ://docs.python.org/3/library/xml.etree.elementtree.html
[4] http://www.pythonware.com/products/pil/