6

我正在比较读取包含文件的行数的性能。

我首先使用 wc 命令行工具完成了它:

$ time wc -l bigFile.csv
1673820 bigFile.csv

real    0m0.157s
user    0m0.124s
sys     0m0.062s

然后在一个干净的 Pharo Core Smalltalk 最新的 1.3

| file lineCount |
Smalltalk garbageCollect.
( Duration milliSeconds: [ file := FileStream readOnlyFileNamed: 'bigFile.csv'.
lineCount := 0.
[ file atEnd ] whileFalse: [
    file nextLine.
    lineCount := lineCount + 1 ].
file close.
lineCount. ] timeToRun ) asSeconds. 
15

如何加快 Smalltalk 代码的速度,使其比 wc 性能更快或更接近?

4

2 回答 2

9
[ (PipeableOSProcess waitForCommand: 'wc -l /path/to/bigfile2.csv') output ] timeToRun.

上面报告了~207毫秒,其中时间报告:

real    0m0.160s
user    0m0.131s
sys     0m0.029s

我在开玩笑,但也是认真的。无需重新发明轮子。FFI、OSProcess、Zinc 等提供了充分的机会来利用诸如 UNIX 实用程序之类的东西,这些实用程序已经过数十年的实战考验。

如果您的问题更多地是关于 Smalltalk 本身,那么首先应该是:

[ FileStream 
    readOnlyFileNamed: '/path/to/reallybigfile2.csv'
    do: [ :file | | endings count |
        count := 0.
        file binary.
        file contents do: [ :c | c = 10 ifTrue: [ count := count + 1 ] ].
        count ]
] timeToRun.

这将使您缩短到 2.5 秒:

  • 使流二进制保存约 10 秒
  • readOnlyFileNamed:do: 保存 ~1 秒
  • 手动查找行尾而不是使用 #nextLine 节省了约 4 秒

一个更干净但长 1/2 秒的操作将是:

file contents occurrencesOf: 10.

当然,如果需要更好的性能,而您又不想使用 FFI/OSProcess,那么您将编写一个插件。

于 2011-11-07T20:10:50.273 回答
2

如果您有能力读取内存中的整个文件,那么最简单的代码是

[ FileStream 
    readOnlyFileNamed: '/path/to/reallybigfile2.csv'
    do: [ :file | file contents lineCount ]
] timeToRun.

这将处理 LF (Linux)、CR (Old Mac)、CR-LF (你可以命名) 的动物园。Sean 的代码只处理 LF,成本大致相同。对于此类基本操作,我认为 Smalltalk 与 C 的因子为 10,因此我怀疑您在不添加自己的原语的情况下会获得更高的效率。

于 2012-06-04T12:35:24.373 回答