A наивный подход может быть просто:
awk '{ print NF " " $0 }' infile| sort -k1,1nr |
awk '{ $1=""; print $0 }' >outfile
Это сохранит занятость до 3 процессоров. sort
не ограничен объемом доступной физической памяти, используйте переключатели -S
и -T
для настройки объема используемой памяти (-S
) перед использованием временных файлов во временном каталоге (-T
) на достаточно большом (и в идеале быстром) разделе.
Если вы можете создать несколько входных файлов , поделив работу, ведущую к этапу сортировки, вы сможете:
for FILE in infile.* ; do
awk '{ print NF " " $0 }' $FILE | sort -k1,1nr >$FILE.tmp&
done
wait
sort -k1,1nr -m infile.*.tmp | awk '{ $1=""; print $0 }' >outfile
rm -f infile.*.tmp
Это будет использовать до N*2
процессоров; более того, последний вид (сортировка слиянием) очень эффективен.
Дальнейшее уточнение для улучшения параллелизма до N*2+1
с использованием FIFO вместо промежуточных файлов, опять же при условии, что возможно несколько входных файлов:
for FILE in infile.* ; do
mkfifo $FILE.fifo
awk '{ print NF " " $0 }' $FILE | sort -k1,1nr >$FILE.fifo&
done
sort -k1,1nr -m infile.*.fifo | awk '{ $1=""; print $0 }' >outfile
rm -f infile.*.fifo
Если несколько входных файлов невозможны , вы можете имитировать их (добавляя накладные расходы ввода / вывода, которые, как мы надеемся, будут амортизироваться количеством доступных процессов):
PARALLELISM=5 # I want 5 parallel instances
for N in `seq $PARALLELISM` ; do
mkfifo infile.$N.fifo
awk 'NR % '$PARALLELISM'=='$N' { print NF " " $0 }' infile |
sort -k1,1nr >infile.$N.fifo&
done
sort -k1,1nr -m infile.*.fifo | awk '{ $1=""; print $0 }' >outfile
rm -f infile.*.fifo
Поскольку мы используем модуль по строковому номеру, у нас хорошая локальность, и кеш файловой системы в идеале должен довести стоимость чтения входного файла снова и снова в $PARALLELISM
процессах до нуля.
Еще лучше , чтение входного файла только один раз и округление входных строк в несколько sort
каналов:
PARALLELISM=5 # I want 5 parallel instances
for N in `seq $PARALLELISM` ; do
mkfifo infile.$N.fifo1
mkfifo infile.$N.fifo2
sort -k1,1nr infile.$N.fifo1 >infile.$N.fifo2&
done
awk '{ print NF " " $0 >("infile." NR % '$PARALLELISM' ".fifo1") }' infile&
sort -k1,1nr -m infile.*.fifo2 | awk '{ $1=""; print $0 }' >outfile
rm -f infile.$N.fifo[12]
Вы должны измерить производительность для различных значений $PARALLELISM
, а затем выбрать оптимальное.
EDIT
Как показано в других сообщениях, вы, конечно, можете использовать cut
вместо окончательного awk
(то есть, который удаляет первый столбец) для потенциально лучшей эффективности. :)
EDIT2
Обновлены все сценарии для предоставленного вами соглашения об именах файлов и исправлена ошибка в последней версии.
Кроме того, при использовании нового соглашения об именах файлов, если ввод / вывод не является узким местом, тогда очень небольшое отклонение от решений dave
/ niry
, вероятно, должно быть еще более эффективным:
for FILE in infile.* ; do
awk '{ print >sprintf("tmpfile.%05d.%s", NF, FILE) }' \
FILE=`basename $FILE` $FILE&
done
wait
ls -1r tmpfile.* | xargs cat >outfile
rm -f tmpfile.*