Как эмулировать w c -l в раку - PullRequest
9 голосов
/ 28 февраля 2020

В perl 5 вы можете эмулировать wc -l с помощью oneliner:

perl -lnE 'END {say $.}' test.txt

Как реализовать эту функцию в Raku

Если вы попытаетесь реализовать это:

raku -e 'say "test.txt".IO.open.lines.elems'

оказывается медленным и использует много памяти

Информация для воспроизведения:

$ wget http://eforexcel.com/wp/wp-content/uploads/2017/07/1500000%20Sales%20Records.zip
$ unzip "1500000 Sales Records.zip"
$ mv "1500000 Sales Records.csv" part.txt
$ for i in `seq 1 10`; do cat part.txt >> test.txt ; done
$ du -sh test.txt
1.8G    test.txt

$ time wc -l test.txt
15000000 test.txt

real    0m0,350s
user    0m0,143s
sys     0m0,205s

$ time perl -lnE 'END { say $. }' test.txt
15000001

real    0m1,981s
user    0m1,719s
sys     0m0,256s

$ time raku -e 'say "test.txt".IO.open.lines.elems'
15000001

real    2m51,852s
user    0m25,129s
sys     0m6,378s

# Using swap (maximum uses 2.2G swap):
# Before `raku -e ''`

$ free -m
              total        used        free      shared  buff/cache   available
Mem:          15009        1695       12604         107         708       12917
Swap:          7583           0        7583

# After `raku -e ''`

$ free -m
              total        used        free      shared  buff/cache   available
Mem:          15009         752       13923          72         332       13899
Swap:          7583         779        6804

# Swap not used
$ time raku -ne '++$ andthen END .say' test.txt
15000001

real    1m44,906s
user    2m14,165s
sys     0m0,653s

$ raku -v
This is Rakudo version 2019.11 built on MoarVM version 2019.11
implementing Perl 6.d.

1 Ответ

8 голосов
/ 28 февраля 2020

Один вариант, который все еще может быть довольно медленным по сравнению с perl, но его стоит сравнить:

raku -ne '++$ andthen END .say' test.txt

Параметр командной строки l является избыточным.

$ - это скаляр анонимного состояния.

andthen проверяет, что определены его lhs, и, если да, устанавливает это значение как топи c ($_ ), а затем оценивает его rhs.

END аналогично perl END. Обратите внимание, что он возвращает Nil в andthen, но это не имеет значения, потому что мы используем оператор END для его побочного эффекта.

Несколько факторов влияют на скорость этого кода , Некоторые вещи, о которых я могу подумать:

  • Затраты на запуск компилятора. Игнорируя любые используемые модули, компилятор raku Rakudo имеет нагрузку на запуск около десятой части секунда на типичном оборудовании по сравнению с довольно незначительным для perl.

  • Понятие "линия". В perl, понятие по умолчанию Обработка строки читает серию байтов, некоторые из которых представляют конец строки. В raku стандартным понятием обработки строки является чтение строки UTF-8, часть которой представляет конец строки. Таким образом, perl несет только накладные расходы на чтение декодера ASCII (или Extended ASCII), тогда как raku накладывает накладные расходы на чтение декодера UTF-8.

  • Оптимизация компилятора . perl обычно оптимизируется до макс. Меня не удивит, если perl -lnE 'END {say $.}' test.txt использует некоторые умные оптимизации. В отличие от этого, работа по оптимизации Rakudo все еще находится на начальном этапе, если говорить относительно.

Единственные вещи, которые я думаю, что каждый может сделать с первым и последним из трех пунктов, которые я упомянул выше нужно подождать N лет и / или внести свой вклад в улучшение компилятора.

Будет способ обойти UTF-8 по умолчанию в raku. Возможно, что-то вроде следующего уже выполнимо и значительно быстрее, чем стандартное значение raku, по крайней мере игнорируя издержки использования модуля с именем foo:

raku -Mfoo -ne '++$ andthen END .say' test.txt

, где module foo переключает кодировку по умолчанию для файла I / O в ASCII или что-либо из доступных кодировок .

Я не проверял, что это реально выполнимо в текущем Rakudo, но был бы удивлен, если бы не было.

...