Сравнение новой строки подсчитывает скорость между wc и Smalltalk - PullRequest
5 голосов
/ 07 ноября 2011

Я сравниваю производительность для чтения того, сколько строк содержит файл.

Сначала я сделал это с помощью инструмента командной строки 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?

Ответы [ 2 ]

8 голосов
/ 08 ноября 2011
[ (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 секунды

Более чистый, но более длительный полдня операции будет:

file contents occurrencesOf: 10.

Конечно, если требуется лучшая производительность, и вы не хотите использовать FFI / OSProcess, вы бы тогда написали плагин.

1 голос
/ 04 июня 2012

Если вы можете позволить себе чтение всего файла в памяти, тогда самый простой код -

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

Это будет обрабатывать зоопарк LF (Linux), CR (Old Mac), CR-LF (вы называете это). Код от Шона обрабатывает только LF, примерно за ту же цену. Я бы сказал, что для таких основных операций ожидается коэффициент 10 для Smalltalk против C, поэтому я сомневаюсь, что вы получите гораздо большую эффективность без добавления собственных примитивов.

...