Bir komut dosyasını çalıştırmanın en hızlı yolu nedir?


22

Bir betiği çalıştırmanın en hızlı yolunun ne olduğunu merak ediyordum, betiğin çıktısını terminalde gösterme, onu bir dosyaya veya belki de yönlendirmeye arasında hız farkı olduğunu okuyordum /dev/null.

Eğer çıktı önemli değilse, senaryonun daha hızlı çalışmasına rağmen senaryoyu daha hızlı çalışmanın en hızlı yolu nedir?

bash ./myscript.sh 
-or-
bash ./myscript.sh > myfile.log
-or-
bash ./myscript.sh > /dev/null


"Düzenli dosyaya yönlendirmek" ve "/ dev / null" a yeniden yönlendirme karşılaştırmak bana çok garip geliyor ...
el.pescado

Yanıtlar:


31

Bu günlerde terminaller eskisinden daha yavaştır, çünkü grafik kartları artık 2B hızlanmayı umursamıyor. Dolayısıyla, bir terminale yazdırmak, özellikle kaydırma söz konusu olduğunda bir komut dosyasını yavaşlatabilir.

Sonuç olarak ./script.sh, daha yavaş ./script.sh >script.log, hangisi daha yavaş /script.sh >/dev/null, çünkü ikincisi daha az çalışmayı gerektirir. Ancak bunun herhangi bir pratik amaç için yeterince fark yaratıp yaratmadığı, betiğinizin ne kadar çıktı ürettiğine ve ne kadar hızlı olduğuna bağlıdır. Komut dosyanız 3 satır yazıyor ve çıkıyorsa veya birkaç saatte bir 3 sayfa yazdırıyorsa, muhtemelen yeniden yönlendirmelerle uğraşmanıza gerek yoktur.

Düzenleme: Bazı hızlı (ve tamamen kırılmış) kriterler:

  • Bir Linux konsolunda, 240x75:

    $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done)
    real    3m52.053s
    user    0m0.617s
    sys     3m51.442s
    
  • Bir xterm, 260x78:

    $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done)
    real    0m1.367s
    user    0m0.507s
    sys     0m0.104s
    
  • Samsung SSD 850 PRO 512GB diskteki bir dosyaya yönlendirin:

     $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done >file)
     real    0m0.532s
     user    0m0.464s
     sys     0m0.068s
    
  • Yönlendir /dev/null:

     $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done >/dev/null)
     real    0m0.448s
     user    0m0.432s
     sys     0m0.016s
    

6
@Kingofkech saniyede 200 satırdan az. Çok fazla farketmezdi. (Karşılaştırma için timeout 1 yes "This is a looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line"10000+ satırları MBP'mde bir saniyede yazdırır.)
muru

4
@Kingofkech Bu bir komut dosyasıysa, bir dosyayı düzenleyin ve gereksiz çıktılar veren satırı yorumlayın. Özellikle bu 3 milyon kez yürütülen harici bir komut (kabuk yerleşik değil) ise, çok kazanacaksınız ...
jimmij

2
"Eskiden" nin dar bir yorumu için. Bir vt220 terminali bugünün terminal emülatörlerinden çok daha yavaştır. Ayrıca, SUN Sparc iş istasyonlarında (benim kullandıklarım) çok yavaş bir konsola sahiplerdi, bu yüzden daha büyük bir projeyi derlerken çıktının bir dosyaya yönlendirilmesi derleme süresini oldukça hızlandıracaktı.
Kusalananda

1
@Kusalananda Bu xterm, 30 yıl önceki HP Apollo'dakiler, 20 yıl önceki xtermsHP-UX ile karşılaştırıldığında tarama yapmak için kullanılır . Ancak, 15 yıl önceki bir Matrox ekran kartı bulunan bir Linux konsolu, 20 yıl önceki bir S3 kartla aynı Linux konsolundan daha yavaştı. Modern bir kartta yüksek çözünürlüklü çerçeve arabelleğine sahip bir Linux konsolu kullanılamaz. :)
Satō Katsura

6
@Kingofkech Bu yaklaşık 2400 bps. Bazılarımız aslında bu hızlarla yıllarca yaşadı. :)
Satō Katsura

14

Satō Katsura'nın cevabını içgüdüsel olarak kabul ederdim; mantıklı. Ancak, test etmek kolay.

Ekrana bir milyon satır yazmayı, bir dosyaya yazmayı (ekleme) ve yönlendirmeyi test ettim /dev/null. Bunların her birini sırayla test ettim, sonra beş kopya yaptım. Bunlar benim kullandığım komutlar.

$ time (for i in {1..1000000}; do echo foo; done)
$ time (for i in {1..1000000}; do echo foo; done > /tmp/file.log) 
$ time (for i in {1..1000000}; do echo foo; done > /dev/null)

Sonra aşağıdaki toplam süreleri çizdim.

zamana karşı çıktı grafiği

Gördüğünüz gibi, Satō Katsura'nın varsayımları doğruydu. Satō Katsura'nın cevabına göre, sınırlayıcı faktörün çıktı olacağından da şüpheliyim, bu nedenle çıktı seçiminin betiğin genel hızı üzerinde önemli bir etkisi olması muhtemel değildir.

FWIW, orjinal cevabım değişik dosya koduna sahipti ve dosya döngünün içine eklenmiş ve /dev/nullyönlendirildi .

$ rm /tmp/file.log; touch /tmp/file.log; time (for i in {1..1000000}; do echo foo >> /tmp/file.log; done) 
$ time (for i in {1..1000000}; do echo foo > /dev/null; done)

John Kugelman'ın yorumlarda işaret ettiği gibi, bu çok fazla ek yük getirir. Soru durduğunda, onu test etmenin doğru yolu bu değildir, ancak betiği kendi içinden tekrar tekrar açmanın maliyetini açıkça gösterdiği için burada bırakacağım .

zamana karşı çıktı grafiği

Bu durumda, sonuçlar tersine çevrilir.


FWIW Cevabımı hızlı bir kriter ekledi. Özellikle, Linux konsolu> 'dan> 200 kat daha yavaştır xterm; bu da ~ 3 kat daha yavaştır /dev/null.
Satō Katsura

Ayrıca bir miktar sınırlama ile test etmelisiniz. OP'nin çıkışı yaklaşık 200 satır / sn'dir.
muru

@muru: Bir satır yazdırmak, 1/200 saniye beklemek ve sonra tekrarlamak mı istiyorsun? Deneyebilirim, ancak bunun benzer sonuçlar olacağını biliyorum, ancak sinyalin gürültünün üstesinden gelmesi çok daha uzun sürüyor. Her ne kadar belki de analizden önce bekleme süresini çıkarabilirim.
Sparhawk

@Sparhawk bunun gibi bir şey. Bu çıkış seviyesinde, CPU'nun çıkış oranını yavaşlatmadan ekranı güncellemek için bolca vakti olacağını düşünüyorum. Program duraklatmadan hat yaymaktan başka bir şey yapmazsa, terminal tamponları gösterilenden daha hızlı doldurulur ve bir tıkanıklık yaratır.
muru

3

Bir betiği hızlandırmanın başka bir yolu da daha hızlı bir kabuk yorumlayıcısı kullanmaktır. Bir hıza karşılaştırın POSIX altında çalışacak meşgul döngü, bash v4.4 , ksh v93u + 20120801 ve dash v0.5.8 .

  1. bash:

    time echo 'n=0;while [ $n -lt 1000000 ] ; do \
                      echo $((n*n*n*n*n*n*n)) ; n=$((n+1)); 
                   done' | bash -s > /dev/null

    Çıktı:

    real    0m25.146s
    user    0m24.814s
    sys 0m0.272s
  2. ksh:

    time echo 'n=0;while [ $n -lt 1000000 ] ; do \
                      echo $((n*n*n*n*n*n*n)) ; n=$((n+1)); 
                   done' | ksh -s > /dev/null

    Çıktı:

    real    0m11.767s
    user    0m11.615s
    sys 0m0.010s
  3. dash:

    time echo 'n=0;while [ $n -lt 1000000 ] ; do \
                      echo $((n*n*n*n*n*n*n)) ; n=$((n+1)); 
                   done' | dash -s > /dev/null

    Çıktı:

    real    0m4.886s
    user    0m4.690s
    sys 0m0.184s

İçindeki komutların bir alt kümesibash ve kshiçindeki tüm komutlarla geriye dönük olarak uyumludurdash . bashYalnızca bu alt kümedeki komutları kullanan bir komut dosyası çalışmalıdır dash.

bashYeni özellikler kullanan bazı komut dosyaları başka bir tercümana dönüştürülebilir. Eğer bashkomut yeni özelliklerle dayanır, bu zahmet değer olmayabilir - bazı yeni bashözellikler hem kod daha kolay iyileştirmeler vardır ve (rağmen daha verimli, bashböylece o genellikle yavaş olmak üzere) dashçalıştıran dahil olabilir (eşdeğer diğer birkaç komut), daha yavaş olurdu.

Şüpheniz olduğunda, bir test yapın ...


bash betiğimi oruç tutabilmek için, onları bash veya ksh olarak yeniden mi yazmam gerekiyor?
Kingofkech

@Kingofkech Bu bash için yazdığınız kod kolayca doğru ksh veya çizgi kodu olabilir. Sadece tercümanı değiştirmeyi dene.
bli
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.