Как заставить команду awk работать быстрее на больших файлах данных - PullRequest
0 голосов
/ 02 октября 2018

Я использовал эту команду awk ниже, чтобы создать новый столбец UUID в таблице в моих существующих .dat файлах.

$ awk '("uuidgen" | getline uuid) > 0 {print uuid "|" $0} {close("uuidgen")}' $filename > ${filename}.pk

Проблема в том, что мои .dat файлы довольно большие (например, 50-60 ГБ), и эта команда awk занимает часы даже для небольших файлов данных (например, 15 МБ).

Есть ли способ увеличить скорость этой команды awk?

Ответы [ 3 ]

0 голосов
/ 02 октября 2018

Интересно, могли бы вы сэкономить время, не открывая и не закрывая awk uuidgen каждую строку.

$ function regen() { while true; do uuidgen; done; }
$ coproc regen
$ awk -v f="$filename" '!(getline line < f){exit} {print $0,line}' OFS="|" < /dev/fd/${COPROC[0]} > "$filename".pk

При этом awk считывает ваше "настоящее" имя файла из переменной и uuid из stdinпотому что вызов uuidgen обрабатывается с помощью bash " coprocess ".Самое интересное в getline состоит в том, чтобы сказать awk, что нужно выйти, когда закончится ввод из $filename.Кроме того, обратите внимание, что awk получает ввод от перенаправления ввода вместо непосредственного чтения файла.Это важно;дескриптор файла на /dev/fd/## является bash , и awk не может его открыть.

Теоретически это должно сэкономить ваше время на выполнение ненужных системных вызовов для открытия, запуска и закрытия uuidgen двоичный.С другой стороны, сопроцесс в любом случае делает почти то же самое, выполняя uuidgen в цикле.Возможно, вы увидите некоторое улучшение в среде SMP.У меня нет текстового файла на 50 ГБ, пригодного для сравнительного анализа.Мне бы очень хотелось услышать ваши результаты.

Обратите внимание, что coproc - это функция, которая была представлена ​​в bash версии 4. А для использования /dev/fd/* требуется, чтобы bash был скомпилирован с поддержкой файловых дескрипторов.В моей системе это также означает, что я должен убедиться, что fdescfs(5) смонтирован.


Я только что заметил в своей системе следующее (FreeBSD 11):

$ /bin/uuidgen -
usage: uuidgen [-1] [-n count] [-o filename]

Если ваш uuidgen также имеет опцию -n, то добавление его в вашу функцию regen() со значением ЛЮБОЕ может быть полезной оптимизацией, чтобы уменьшить количество повторных открытий команды.Например:

$ function regen() { while true; do uuidgen -n 100; done; }

Это приведет к тому, что uuidgen будет вызываться только один раз каждые 100 строк ввода, а не для каждой строки.


А если вы работаете в Linux,в зависимости от того, как вы настроены, у вас может быть альтернативный источник для UUID.Примечание:

$ awk -v f=/proc/sys/kernel/random/uuid '{getline u<f; close(f); print u,$0}' OFS="|" "$filename" "$filename".pk

Для этого не требуется bash coproc, он просто читает awk случайным образом uuid непосредственно из функции ядра Linux, которая их предоставляет.Вы по-прежнему закрываете дескриптор файла для каждой строки ввода, но, по крайней мере, вам не нужно выполнять исполняемый файл uuidgen.

YMMV.Я не знаю, с какой ОС вы работаете, поэтому я не знаю, что может сработать для вас.

0 голосов
/ 02 октября 2018

Ваш скрипт вызывает shell для вызова awk для вызова shell для вызова uuidgen.Awk - это инструмент для работы с текстом, это не оболочка (среда, из которой можно вызывать другие инструменты), поэтому не делайте этого, просто вызовите uuidgen из оболочки:

$ cat file
foo .*
bar stuff
here

$ xargs -d $'\n' -n 1 printf '%s|%s\n' "$(uuidgen)" < file
5662f3bd-7818-4da8-9e3a-f5636b174e94|foo .*
5662f3bd-7818-4da8-9e3a-f5636b174e94|bar stuff
5662f3bd-7818-4da8-9e3a-f5636b174e94|here
0 голосов
/ 02 октября 2018

Я просто предполагаю, что настоящая проблема здесь в том, что вы запускаете подпроцесс для каждой строки.Вы можете прочитать ваш файл явно построчно и построчно прочитать вывод из batch-uuidgen, и, таким образом, одновременно обработать только один подпроцесс.К сожалению, uuidgen не работает таким образом.

Может быть, другое решение?

perl -MData::UUID -ple 'BEGIN{ $ug = Data::UUID->new } $_ = lc($ug->to_string($ug->create)) . " | " . $_' $filename > ${filename}.pk

Может ли это быть быстрее?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...