У меня уникальная ситуация, когда я могу сравнить решения, предложенные на этой странице, и поэтому я пишу этот ответ как консолидацию предложенных решений с включенным временем выполнения для каждого.
Настроить
У меня есть файл текстовых данных ASCII 3,261 гигабайта с одной парой ключ-значение на строку. Файл содержит 3,339,550,320 строк в общей сложности и не открывается в любом редакторе, который я пробовал, включая мой переход к Vim. Мне нужно поместить этот файл в подмножество, чтобы исследовать некоторые из обнаруженных мной значений, начиная только с строки ~ 500 000 000.
Поскольку файл имеет так много строк:
- Мне нужно извлечь только подмножество строк, чтобы сделать что-нибудь полезное с данными.
- Чтение каждой строки, приводящей к ценностям, которые меня интересуют, займет много времени.
- Если решение прочитает строки, которые мне интересны, и продолжит чтение остальной части файла, оно потратит время на чтение почти 3 миллиардов ненужных строк и займет в 6 раз больше времени, чем необходимо.
Мой лучший вариант развития событий - это решение, которое извлекает только одну строку из файла, не считывая другие строки в файле, но я не могу думать о том, как бы это сделать в Bash.
В целях моего здравомыслия я не собираюсь читать полные 500 000 000 строк, которые мне нужны для моей собственной проблемы. Вместо этого я попытаюсь извлечь строку 50 000 000 из 3 339 550 320 (что означает, что чтение полного файла займет в 60 раз больше времени, чем необходимо).
Я буду использовать time
встроенный для тестирования каждой команды.
базисный
Сначала давайте посмотрим, как head
tail
решение:
$ time head -50000000 myfile.ascii | tail -1
pgm_icnt = 0
real 1m15.321s
Базовая линия для строки 50 миллионов составляет 00: 01: 15.321, если бы я сразу выбрал строку 500 миллионов, это, вероятно, составило бы ~ 12,5 минут.
резать
Я сомневаюсь в этом, но оно того стоит:
$ time cut -f50000000 -d$'\n' myfile.ascii
pgm_icnt = 0
real 5m12.156s
Для этого потребовалось 00: 05: 12.156, что намного медленнее, чем базовый уровень! Я не уверен, прочитал ли он весь файл или только до 50 миллионов строк перед остановкой, но, несмотря на это, это не кажется эффективным решением проблемы.
AWK
Я запустил решение только exit
потому, что не собирался ждать запуска полного файла:
$ time awk 'NR == 50000000 {print; exit}' myfile.ascii
pgm_icnt = 0
real 1m16.583s
Этот код работал в 00: 01: 16.583, что всего на ~ 1 секунду медленнее, но все же не улучшило базовый уровень. При такой скорости, если команда выхода была исключена, вероятно, потребовалось бы ~ 76 минут, чтобы прочитать весь файл!
Perl
Я также запустил существующее решение Perl:
$ time perl -wnl -e '$.== 50000000 && print && exit;' myfile.ascii
pgm_icnt = 0
real 1m13.146s
Этот код работал в 00: 01: 13.146, что примерно на 2 секунды быстрее, чем базовый уровень. Если бы я запустил его на 500 000 000, это заняло бы ~ 12 минут.
СЭД
Главный ответ на доске, вот мой результат:
$ time sed "50000000q;d" myfile.ascii
pgm_icnt = 0
real 1m12.705s
Этот код работал в 00: 01: 12.705, что на 3 секунды быстрее, чем базовая линия, и на ~ 0,4 секунды быстрее, чем Perl. Если бы я запустил все 500 000 000 строк, это заняло бы ~ 12 минут.
файле проекта
У меня есть bash 3.1, и поэтому я не могу проверить решение mapfile.
Вывод
Похоже, что по большей части трудно улучшить head
tail
решение. В лучшем случае sed
решение обеспечивает повышение эффективности на ~ 3%.
(проценты рассчитываются по формуле % = (runtime/baseline - 1) * 100
)
Ряд 50 000 000
- 00: 01: 12,705 (-00: 00: 02,616 = -3,47%)
sed
- 00: 01: 13.146 (-00: 00: 02.175 = -2,89%)
perl
- 00: 01: 15,321 (+00: 00: 00.000 = + 0,00%)
head|tail
- 00: 01: 16,583 (+00: 00: 01.262 = + 1,68%)
awk
- 00: 05: 12,156 (+00: 03: 56,835 = + 314,43%)
cut
Ряд 500 000 000
- 00: 12: 07.050 (-00: 00: 26.160)
sed
- 00: 12: 11.460 (-00: 00: 21.750)
perl
- 00: 12: 33.210 (+00: 00: 00.000)
head|tail
- 00: 12: 45.830 (+00: 00: 12.620)
awk
- 00: 52: 01.560 (+00: 40: 31.650)
cut
Строка 3,338,559,320
- 01: 20: 54.599 (-00: 03: 05.327)
sed
- 01: 21: 24.045 (-00: 02: 25.227)
perl
- 01: 23: 49.273 (+00: 00: 00.000)
head|tail
- 01: 25: 13.548 (+00: 02: 35.735)
awk
- 05: 47: 23.026 (+04: 24: 26.246)
cut
awk
и,sed
и я уверен, что кто-то может придумать Perl с одной