Tôi có một tình huống duy nhất là tôi có thể điểm chuẩn các giải pháp được đề xuất trên trang này và vì vậy tôi đang viết câu trả lời này dưới dạng hợp nhất các giải pháp được đề xuất với thời gian chạy bao gồm cho mỗi giải pháp.
Thiết lập
Tôi có tệp dữ liệu văn bản ASCII 3.261 gigabyte với một cặp khóa-giá trị mỗi hàng. Tổng cộng có tổng số 3.339.550.320 hàng và bất chấp mở trong bất kỳ trình chỉnh sửa nào tôi đã thử, bao gồm cả Vim của tôi. Tôi cần phải đặt tập tin này để điều tra một số giá trị mà tôi đã phát hiện ra chỉ bắt đầu quanh hàng ~ 500.000.000.
Bởi vì tệp có rất nhiều hàng:
- Tôi chỉ cần trích xuất một tập hợp con của các hàng để làm bất cứ điều gì hữu ích với dữ liệu.
- Đọc qua từng hàng dẫn đến các giá trị tôi quan tâm sẽ mất nhiều thời gian.
- Nếu giải pháp đọc qua các hàng tôi quan tâm và tiếp tục đọc phần còn lại của tệp, nó sẽ lãng phí thời gian để đọc gần 3 tỷ hàng không liên quan và mất nhiều thời gian hơn 6 lần so với cần thiết.
Kịch bản trường hợp tốt nhất của tôi là một giải pháp chỉ trích xuất một dòng duy nhất từ tệp mà không đọc bất kỳ hàng nào khác trong tệp, nhưng tôi không thể nghĩ về cách tôi sẽ thực hiện điều này trong Bash.
Vì mục đích của sự tỉnh táo của tôi, tôi sẽ không cố gắng đọc toàn bộ 500.000.000 dòng tôi cần cho vấn đề của riêng tôi. Thay vào đó, tôi sẽ cố gắng trích xuất hàng 50.000.000 trong số 3.339.550.320 (có nghĩa là đọc toàn bộ tệp sẽ mất 60 lần lâu hơn mức cần thiết).
Tôi sẽ sử dụng tích time
hợp sẵn để đánh giá từng lệnh.
Đường cơ sở
Trước tiên hãy xem cách head
tail
giải quyết:
$ time head -50000000 myfile.ascii | tail -1
pgm_icnt = 0
real 1m15.321s
Đường cơ sở cho hàng 50 triệu là 00: 01: 15.321, nếu tôi đi thẳng cho hàng 500 triệu thì có thể là ~ 12,5 phút.
cắt
Tôi không biết điều này, nhưng nó đáng để thử:
$ time cut -f50000000 -d$'\n' myfile.ascii
pgm_icnt = 0
real 5m12.156s
Cái này mất 00: 05: 12.156 để chạy, chậm hơn nhiều so với đường cơ sở! Tôi không chắc liệu nó có đọc qua toàn bộ tệp hay chỉ lên tới 50 triệu trước khi dừng, nhưng bất kể điều này có vẻ không phải là một giải pháp khả thi cho vấn đề.
AWK
Tôi chỉ chạy giải pháp với exit
vì tôi sẽ không đợi tệp đầy đủ chạy:
$ time awk 'NR == 50000000 {print; exit}' myfile.ascii
pgm_icnt = 0
real 1m16.583s
Mã này chạy trong 00: 01: 16.583, tốc độ chỉ chậm hơn ~ 1 giây, nhưng vẫn không phải là một cải tiến trên đường cơ sở. Với tốc độ này nếu lệnh thoát đã bị loại trừ, có lẽ sẽ mất khoảng 76 phút để đọc toàn bộ tệp!
Perl
Tôi cũng đã chạy giải pháp Perl hiện có:
$ time perl -wnl -e '$.== 50000000 && print && exit;' myfile.ascii
pgm_icnt = 0
real 1m13.146s
Mã này chạy trong 00: 01: 13.146, nhanh hơn ~ 2 giây so với đường cơ sở. Nếu tôi chạy nó với đầy đủ 500.000.000, có thể sẽ mất ~ 12 phút.
quyến rũ
Câu trả lời hàng đầu trên bảng, đây là kết quả của tôi:
$ time sed "50000000q;d" myfile.ascii
pgm_icnt = 0
real 1m12.705s
Mã này chạy trong 00: 01: 12.705, nhanh hơn 3 giây so với đường cơ sở và nhanh hơn ~ 0,4 giây so với Perl. Nếu tôi chạy nó trên toàn bộ 500.000.000 hàng, có thể mất khoảng 12 phút.
mapfile
Tôi có bash 3.1 và do đó không thể kiểm tra giải pháp mapfile.
Phần kết luận
Có vẻ như, đối với hầu hết các phần, thật khó để cải thiện head
tail
giải pháp. Tốt nhất là sed
giải pháp cung cấp hiệu quả tăng ~ 3%.
(tỷ lệ phần trăm được tính theo công thức % = (runtime/baseline - 1) * 100
)
Hàng 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 (GIÁ: 00: 00.000 = + 0,00%)
head|tail
- 00: 01: 16.583 (GIÁ: 00: 01.262 = + 1.68%)
awk
- 00: 05: 12.156 (GIÁ: 03: 56.835 = + 314,43%)
cut
Hàng 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 (GIÁ: 00: 00.000)
head|tail
- 00: 12: 45.830 (GIÁ: 00: 12.620)
awk
- 00: 52: 01.560 (GIÁ: 40: 31.650)
cut
Hàng 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 (GIÁ: 00: 00.000)
head|tail
- 01: 25: 13,548 (GIÁ: 02: 35.735)
awk
- 05: 47: 23.026 (+04: 24: 26.246)
cut
awk
vàsed
và tôi chắc chắn rằng ai đó cũng có thể đưa ra một lớp lót Perl hoặc tương tự;)