Как ksh93 так быстро?

9

Итак, в общем, я склонен обращать внимание на sedобработку текста - особенно для больших файлов - и обычно избегаю делать подобные вещи в самой оболочке.

Однако я думаю, что это может измениться. Я искал вокруг, man kshи я заметил это:

<#pattern     Seeks forward to the beginning of the
              next line containing pattern.

<##pattern    The same as <# except that  the  por
              tion  of  the file that is skipped is
              copied to standard output.

Скептически относясь к реальной полезности, я решил попробовать. Я сделал:

seq -s'foo bar
' 1000000 >file

... для миллиона строк данных, которые выглядят так:

1foo bar
...
999999foo bar
1000000

... и противопоставил это sedкак:

p='^[^0-8]99999.*bar'
for c in "sed '/$p/q'" "ksh -c ':<##@(~(E)$p)'"    
do </tmp/file eval "time ( $c )"
done | wc -l

Таким образом, обе команды должны получить до 999999foo bar, и их реализация сопоставления с образцом должна оценивать как минимум начало и конец каждой строки, чтобы сделать это. Они также должны проверить первый символ по отрицательному шаблону. Это простая вещь, но ... Результаты оказались не такими, как я ожидал:

( sed '/^[^0-8]99999.*bar/q' ) \
    0.40s user 0.01s system 99% cpu 0.419 total
( ksh -c ':<##@(~(E)^[^0-8]99999.*bar)' ) \
    0.02s user 0.01s system 91% cpu 0.033 total
1999997

kshиспользует ERE здесь и sedBRE. Я делал то же самое с kshшаблоном оболочки, но результаты не отличались.

Во всяком случае, это довольно существенное расхождение - kshпревосходит в sed10 раз. Я читал ранее, что Дэвид Корн написал свою собственную библиотеку IO и реализует ее в ksh- возможно, это связано? - но я почти ничего не знаю об этом. Как это оболочка делает это так хорошо?

Еще более удивительным для меня является то, что он kshдействительно оставляет свое смещение там, где вы его просите. Чтобы получить (почти) то же самое из (GNU), sed вы должны использовать -u- очень медленно .

Вот тест grepv.ksh

1000000         #grep + head
( grep -qm1 '^[^0-8]99999.*bar'; head -n1; ) \
    0.02s user 0.00s system 90% cpu 0.026 total
999999foo bar   #ksh + head
( ksh -c ':<#@(~(E)^[^0-8]99999.*bar)'; head -n1; )  \
    0.02s user 0.00s system 73% cpu 0.023 total

kshбьет grepздесь - но это не всегда - они в значительной степени связаны. Тем не менее, это довольно отлично, и ksh обеспечивает предварительный просмотр - headввод начинается до его совпадения.

Кажется, это слишком хорошо, чтобы быть правдой. Что эти команды делают по-другому под капотом?

Ох, и, видимо, здесь даже нет подоболочки:

ksh -c 'printf %.5s "${<file;}"'
mikeserv
источник
Это patternрегулярное выражение или более простой шаблон оболочки?
Муру
@muru - Может быть и так, но я не очень хорошо меняю окружающих. В примере это шаблон оболочки - по умолчанию.
mikeserv
@muru - я добавил один с регулярным выражением.
mikeserv

Ответы:

8

Ksh не только использует sfio, но и использует собственный распределитель памяти.

Тем не менее, я думаю, что Sfio имеет значение в этом случае. Я только что попытался запустить ваш пример под strace и вижу, что ksh вызывает чтение / запись ~ 200 раз (блоки по 65 КБ), а sed делает это ~ 3400 раз (блоки по 4 КБ). С sed -u мой ноутбук почти растаял, чтение выполняется за байт, а запись - за строку. Кш просто использует lseek. Grep использует чтение ~ 400 раз (блоки 32 КБ).

Мирослав Франк
источник
Да - небуферизованный не для слабонервных. Интересно, эффективен ли kshдвижок регулярных выражений в качестве io? В любом случае, большое спасибо за ответ. Мои извинения вашему ноутбуку. А как насчет пользовательского распределителя памяти? У вас есть еще что-нибудь об этом?
mikeserv
1
К сожалению нет. Конечно, вы можете скачать исходный код с сайта & & t, но это все. Библиотека называется AST и содержит распределитель, движок регулярных выражений и многое другое. Так что вполне возможно, что комбинация всех этих вещей делает ksh намного быстрее.
Мирослав Франк
Спасибо - это выглядит многообещающе: некоторые компоненты, доступные в коллекции программного обеспечения AST: Команды POSIX Большинство стандартных команд POSIX доступны в коллекции AST. Многие кодируются как библиотечные функции, которые могут быть добавлены в ksh как встроенная команда, что значительно повышает производительность. - Теперь я просто должен понять, как его построить,
mikeserv
1
@mikeserv ksh может быть построен для использования vmalloc- распределителя Phong Vo . Журнальные статьи доступны по этой ссылке.
Марк Плотник