13

考虑这个 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

所以,我怀疑我的问题的答案只是一个简单的“不”。

另请注意,我的真实程序正在做一些比仅仅计算行数更有趣的事情,所以请给出一个通用的答案,而不是行数技巧(比如在文件中保留行数元数据)

PS:我标记了“linux”这个问题,因为我只对特定于 linux 的答案感兴趣。随意给出与操作系统无关的,甚至是其他操作系统的答案,如果你有的话。

另请参阅后续问题

4

8 回答 8

12

把硬件扔到问题上。

正如 gs 所指出的,您的瓶颈是硬盘传输率。所以,不,你不能用更好的算法来改善你的时间,但你可以买一个更快的硬盘。

编辑: gs 的另一个优点;您还可以使用RAID配置来提高速度。这可以通过硬件或软件(例如OS XLinuxWindows Server等)来完成。


控制方程

(Amount to transfer) / (transfer rate) = (time to transfer)

(6000 MB) / (60 MB/s) = 100 seconds

(6000 MB) / (125 MB/s) = 48 seconds


硬件解决方案

ioDrive Duo据说是企业环境中最快的解决方案,“将于 2009 年 4 月上市”。

或者您可以查看 WD Velociraptor 硬盘驱动器 (10,000 rpm)。

此外,我听说 Seagate Cheetah是一个不错的选择(15,000 rpm 和持续 125MB/s 的传输速率)。

于 2009-05-11T19:24:57.657 回答
8

诀窍不是让电子移动得更快(这很难做到),而是在单位时间内完成更多的工作。

首先,确保您读取的 6GB 文件受 I/O 限制,而不是 CPU 限制。

如果它受 I/O 限制,请考虑“扇出”设计模式。

  • 一个父进程产生了一堆子进程。

  • 父级读取 6Gb 文件,并通过写入子级的 STDIN 管道将行发送给子级。6GB 读取时间将保持不变。行处理应尽可能少地涉及父处理。应该使用非常简单的过滤器或计数。

    管道是用于通信的内存通道。它是一个具有读取器和写入器的共享缓冲区。

  • 每个孩子从 STDIN 读取一行,并做适当的工作。每个孩子可能应该编写一个简单的磁盘文件,其中包含最终(汇总,减少)结果。稍后,可以合并这些文件中的结果。

于 2009-05-11T20:06:39.007 回答
5

简单的“不”。

您几乎已经达到了最大磁盘速度。

我的意思是,您可以映射文件,或者以二进制块的形式读取它,然后使用.count('\n')或其他东西。但这不太可能带来重大改进。

于 2009-05-11T17:22:22.740 回答
5

您无法获得比最大磁盘读取速度更快的速度。

为了达到最大磁盘速度,您可以使用以下两个技巧:

  1. 用大缓冲区读入文件。这可以“手动”编码,也可以简单地使用 io.BufferedReader (在 python2.6+ 中可用)。
  2. 在另一个线程中并行计算换行符。
于 2009-05-11T18:53:41.153 回答
4

如果假设磁盘可以读取 60MB/s,则需要 6000 / 60 = 100 秒,即 1 分 40 秒。我不认为你可以更快,因为磁盘是瓶颈。

于 2009-05-11T17:30:53.160 回答
1

正如其他人所说 - “不”

几乎所有的时间都花在等待 IO 上。如果这是您需要多次执行的操作,并且您有一台具有大量内存的机器,则可以将文件保存在内存中。如果您的机器有 16GB 的内存,那么 /dev/shm 将有 8GB 可用。

另一种选择:如果你有多台机器,这个问题很容易并行化。将它拆分到多台机器之间,每台机器都计算换行符,然后添加结果。

于 2009-05-11T17:33:33.610 回答
1

读取整个 6gb 文件大约需要 2 分钟。你可以对算法或操作系统做很多事情来加快速度。我认为你有两个选择:

  1. 花钱解决问题并获得更好的硬件。如果这个项目适合你的工作,这可能是最好的选择。

  2. 不要阅读整个文件。我不知道您要对数据做什么,所以也许您别无选择,只能阅读整个内容。另一方面,如果您正在扫描整个文件以查找特定内容,那么在开始时将一些元数据放在那里可能会有所帮助。

于 2009-05-14T00:54:28.877 回答
0

请注意,Python I/O 是用 C 实现的,因此进一步加速它的运气并不好。

于 2009-05-11T18:55:30.730 回答