У меня есть уникальная ситуация, когда я могу сравнить решения, предложенные на этой странице, и поэтому я пишу этот ответ как консолидацию предложенных решений с включенным временем выполнения для каждого.
Настройка
У меня есть текстовый файл ASCII 3,261 гигабайта с одной парой ключ-значение на строку.Файл содержит 3,339,550,320 строк в общей сложности и не открывается в любом редакторе, который я пробовал, включая мой переход к Vim.Мне нужно установить этот файл на подмножество, чтобы исследовать некоторые из обнаруженных мной значений, начиная только со строки ~ 500 000 000.
Поскольку в файле так много строк:
- Iнужно извлечь только подмножество строк, чтобы сделать что-нибудь полезное с данными.
- Чтение каждой строки, ведущей к значениям, которые мне нужны, займет много времени.
- Еслирешение считывает строки, которые мне интересны, и продолжает читать оставшуюся часть файла, тратит время на чтение почти 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 минут.
cut
Я сомневаюсь в этом,но оно того стоит:
$ 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 минут.
sed
Главный ответ на доске, вот мой результат:
$ time sed "50000000q;d" myfile.ascii
pgm_icnt = 0
real 1m12.705s
Этот код работал в 00: 01: 12.705, что на 3 секунды быстрее, чем базовая линия, и на ~ 0,4 секунды быстрее, чем Perl.Если бы я запустил его на полных 500 000 000 строк, это заняло бы ~ 12 минут.
mapfile
У меня есть 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