Как эмулировать wc -l в Raku

9

В 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.
TheAthlete
источник
3
Не могли бы вы добавить информацию о времени и фактический результат wc(который должен включать размер файла). Спасибо.
Элизабет Маттийсен
Обновление вопроса - добавлен пример для воспроизведения
TheAthlete
2
@TheAthlete Спасибо за добавленную информацию. Я думаю, что, вероятно, это будет исторически интересный [raku] SO из-за предполагаемого устойчивого сокращения разрыва производительности в ближайшие годы в rakudo, поэтому, пожалуйста, рассмотрите возможность добавления еще пары битов информации. Во-первых, хотя ясно, что вы используете недавнее rakudo (потому что вы пишете raku), было бы хорошо иметь raku -vвывод. Также, пожалуйста, рассмотрите возможность добавления выходных данных моего текущего предложения. Кроме того, я могу рассмотреть переход на 'ascii'декодер позже в эти выходные, чтобы лучше провести время.
raiph
1
На заметку: -lфлаг для Perl значительно замедляет Perl, и в этом случае он бесполезен. На моей машине для файла со случайной длиной строки и около 200 тыс. Строк удаление -lприводит к улучшению на 40%.
Сорин

Ответы:

8

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

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

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

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

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

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

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

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

  • Понятие "линия". В perlстандартном понятии обработки строки по умолчанию читается серия байтов, некоторые из которых представляют конец строки. В rakuстандартном понятии обработки строки по умолчанию читается строка UTF-8, часть которой представляет конец строки. Таким образом, perlвозникают только издержки чтения декодера ASCII (или расширенного 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

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

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

raiph
источник