У мене є унікальна ситуація, коли я можу орієнтувати рішення, запропоновані на цій сторінці, і тому я пишу цю відповідь як консолідацію запропонованих рішень із включеним часом виконання для кожного.
Налаштування
У мене є текстовий файл даних 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 хвилин.
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 хвилин.
картографічний файл
У мене bash 3.1, тому не можу перевірити рішення картографічного файлу.
Висновок
Здається, здебільшого важко покращити 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;)