可以加速Python的IO吗?
考虑一下这个Python程序:
import sys
lc = 0
for line in open(sys.argv[1]):
lc = lc + 1
print lc, sys.argv[1]
在我的6GB文本文件上运行它,大约需要2分钟完成。
问题是:有没有可能更快呢?
注意,下面这个程序所需的时间也是一样的:
wc -l myfile.txt
所以,我怀疑我的问题的答案就是简单的“没有”。
另外,我的真实程序做的事情比单纯数行要有趣得多,所以请给一个通用的答案,不要是关于计数行数的小技巧(比如在文件中保存行数的元数据)。
顺便说一下,我把这个问题标记为“linux”,因为我只对Linux特定的答案感兴趣。如果你有其他操作系统的答案,或者是与操作系统无关的答案,也可以随便给我。
另请参见这个后续问题
9 个回答
关键在于不是让电子移动得更快(这很难做到),而是让每单位时间内完成更多的工作。
首先,确保你的6GB文件读取是受I/O限制的,而不是受CPU限制的。
如果是受I/O限制的,可以考虑使用“扇出”设计模式。
一个父进程会生成很多子进程。
父进程读取6GB的文件,然后把数据行分发给子进程,通过写入它们的标准输入管道来实现。读取6GB文件的时间会保持不变。分发数据行时,父进程的处理应该尽量少。可以使用非常简单的过滤或计数。
管道是一种内存中的通信通道。它是一个共享的缓冲区,有一个读取者和一个写入者。
每个子进程从标准输入读取一行数据,并进行相应的处理。每个子进程可能会写一个简单的磁盘文件,保存最终的(汇总、减少)结果。稍后,这些文件中的结果可以进行合并。
用硬件解决问题。
正如gs提到的,你的问题主要是硬盘的传输速度。所以,换个更好的算法是没用的,但你可以买个更快的硬盘。
补充:gs还提到一个好点子;你也可以使用RAID配置来提升速度。这可以通过硬件或软件来实现(例如OS X、Linux、Windows Server等)。
计算公式
(要传输的量) / (传输速度) = (传输时间)
(6000 MB) / (60 MB/s) = 100秒
(6000 MB) / (125 MB/s) = 48秒
硬件解决方案
ioDrive Duo据说是企业环境中最快的解决方案,"将在2009年4月上市"。
你也可以看看WD Velociraptor硬盘(转速10,000转/分钟)。
另外,我听说Seagate的Cheetah也是个不错的选择(转速15,000转/分钟,持续传输速度125MB/s)。
你无法超过硬盘的最大读取速度。
为了达到硬盘的最大速度,你可以使用以下两个小技巧:
- 用一个大一点的缓冲区来读取文件。你可以手动编写代码来实现,或者直接使用 io.BufferedReader(在 python2.6 及以上版本中可用)。
- 在另一个线程中并行进行换行符的计数。