Bu sayfada önerilen çözümleri karşılaştırabileceğim benzersiz bir durum var ve bu yanıtı, önerilen çözümlerin her biri için dahil edilen çalışma süreleriyle birleştirmesi olarak yazıyorum.
Kurmak
Satır başına bir anahtar / değer çifti ile 3.261 gigabayt ASCII metin veri dosyası var. Dosya toplamda 3.339.550.320 satır içeriyor ve go-to Vim dahil olmak üzere denediğim herhangi bir editörde açılan meydan okur. Ben sadece satır ~ 500.000.000 etrafında başlattığım keşfettiğim bazı değerleri araştırmak için bu dosyayı alt kümeye gerekir.
Dosyada çok fazla satır olduğundan:
- Verilerle yararlı bir şey yapmak için satırların yalnızca bir alt kümesini ayıklamak gerekir.
- Değer verdiğim değerlere ulaşan her satırı okumak uzun zaman alacaktır.
- Çözüm, önem verdiğim satırları okur ve dosyanın geri kalanını okumaya devam ederse, neredeyse 3 milyar alakasız satırı okumak için zaman harcar ve gerektiğinden 6 kat daha uzun sürer.
En iyi durum senaryom, dosyadaki diğer satırları okumadan dosyadan yalnızca tek bir satır ayıklayan bir çözümdür, ancak bunu Bash'de nasıl başaracağımı düşünemiyorum.
Akıl sağlığım açısından, kendi sorunum için ihtiyaç duyacağım 500.000.000 satırın tamamını okumaya çalışmayacağım. Bunun yerine, 3.339.550.320'den 50.000.000 numaralı satırı ayıklamaya çalışacağım (bu, tam dosyayı okumak gerektiğinden 60 kat daha uzun sürecek).
time
Her komutu karşılaştırmak için yerleşik olanı kullanacağım.
Temel
İlk önce head
tail
çözümün nasıl olduğunu görelim :
$ time head -50000000 myfile.ascii | tail -1
pgm_icnt = 0
real 1m15.321s
50 milyon satır için taban çizgisi 00: 01: 15.321, eğer 500 milyon satır için düz gidersem muhtemelen ~ 12.5 dakika olurdu.
kesmek
Bundan şüpheliyim, ama denemeye değer:
$ time cut -f50000000 -d$'\n' myfile.ascii
pgm_icnt = 0
real 5m12.156s
Bu, 00: 05: 12.156'yı çalıştırdı, bu da taban çizgisinden çok daha yavaş! Durdurmadan önce dosyanın tamamını mı yoksa sadece 50 milyon satırını mı okuduğundan emin değilim, ancak bu sorun için geçerli bir çözüm gibi görünmüyor.
AWK
Çözümü sadece çalıştırdım exit
çünkü tam dosyanın çalışmasını beklemeyecektim:
$ time awk 'NR == 50000000 {print; exit}' myfile.ascii
pgm_icnt = 0
real 1m16.583s
Bu kod 00: 01: 16.583'te çalıştırıldı, bu sadece ~ 1 saniye daha yavaş, ancak hala taban çizgisinde bir gelişme değil. Bu durumda, çıkış komutu hariç tutulursa, tüm dosyayı okumak yaklaşık ~ 76 dakika sürerdi!
Perl
Mevcut Perl çözümünü de çalıştırdım:
$ time perl -wnl -e '$.== 50000000 && print && exit;' myfile.ascii
pgm_icnt = 0
real 1m13.146s
Bu kod, taban çizgisinden ~ 2 saniye daha hızlı olan 00: 01: 13.146'da yayınlandı. Tam 500.000.000 üzerinde çalıştırırsam, muhtemelen ~ 12 dakika sürer.
sed
Tahtadaki en iyi cevap, işte benim sonucum:
$ time sed "50000000q;d" myfile.ascii
pgm_icnt = 0
real 1m12.705s
Bu kod, taban çizgisinden 3 saniye ve Perl'den ~ 0.4 saniye daha hızlı olan 00: 01: 12.705'te çalıştırıldı. Tam 500.000.000 satırda çalıştırsaydım, muhtemelen ~ 12 dakika sürecekti.
mapfile
Ben bash 3.1 var ve bu nedenle mapfile çözüm test edemez.
Sonuç
Görünüşe göre, çoğunlukla head
tail
çözümü geliştirmek zor . sed
Çözelti en iyi ihtimalle verimde ~% 3 artış sağlar.
(formülle hesaplanan yüzdeler % = (runtime/baseline - 1) * 100
)
Sıra 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
Sıra 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
Sıra 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
vesed
eminim birisi Perl bir astar ya da benzeri ile gelebilir;)