Apa cara tercepat untuk menjalankan skrip?

22

Saya bertanya-tanya apa cara tercepat untuk menjalankan skrip, saya telah membaca bahwa ada perbedaan kecepatan antara menampilkan output skrip di terminal, mengarahkannya ke file atau mungkin /dev/null.

Jadi jika outputnya tidak penting, apa cara tercepat untuk membuat skrip bekerja lebih cepat, bahkan jika minim.

bash ./myscript.sh 
-or-
bash ./myscript.sh > myfile.log
-or-
bash ./myscript.sh > /dev/null
Kingofkech
sumber
Membandingkan "mengarahkan ke file biasa" dan "mengarahkan ke / dev / null" tampak sangat aneh bagi saya ...
el.pescado

Jawaban:

31

Terminal akhir-akhir ini lebih lambat daripada biasanya, terutama karena kartu grafis tidak lagi peduli dengan akselerasi 2D. Jadi memang, mencetak ke terminal dapat memperlambat skrip, terutama saat pengguliran terlibat.

Akibatnya ./script.shlebih lambat daripada ./script.sh >script.log, yang pada gilirannya lebih lambat daripada /script.sh >/dev/null, karena yang terakhir melibatkan lebih sedikit pekerjaan. Namun apakah ini cukup membuat perbedaan untuk tujuan praktis tergantung pada berapa banyak output yang dihasilkan skrip Anda dan seberapa cepat. Jika skrip Anda menulis 3 baris dan keluar, atau jika mencetak 3 halaman setiap beberapa jam, Anda mungkin tidak perlu repot dengan pengalihan.

Sunting: Beberapa tolok ukur cepat (dan benar-benar rusak):

  • Di konsol Linux, 240x75:

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

    $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done)
    real    0m1.367s
    user    0m0.507s
    sys     0m0.104s
  • Redirect ke file, pada disk Samsung SSD 850 PRO 512GB:

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

     $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done >/dev/null)
     real    0m0.448s
     user    0m0.432s
     sys     0m0.016s
Satō Katsura
sumber
6
@ Kingofkech kurang dari 200 baris / detik. Itu tidak akan membuat banyak perbedaan. (Sebagai perbandingan, timeout 1 yes "This is a looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line"cetak 100000+ baris dalam satu detik di MBP saya.)
muru
4
@ Kingofkech Jika ini adalah skrip maka edit file dan beri komentar pada baris yang mencetak output yang tidak perlu. Anda akan mendapatkan banyak, terutama jika ini adalah perintah eksternal (bukan shell built-in) dieksekusi 3 juta kali ...
jimmij
2
Untuk interpretasi yang sempit dari "dulu". Terminal vt220 jauh lebih lambat daripada emulator terminal saat ini. Juga, workstation SUN Sparc (yang saya gunakan) memiliki konsol yang sangat lambat, jadi hanya mengarahkan output ke file ketika mengkompilasi proyek yang lebih besar akan mempercepat waktu kompilasi.
Kusalananda
1
@ Kusalananda Itu benar, ada xtermdi HP Apollo dari 30 tahun yang lalu digunakan untuk merangkak dibandingkan xtermspada HP-UX dari 20 tahun yang lalu. Namun, konsol Linux dengan kartu video Matrox dari 15 tahun yang lalu lebih lambat dari konsol Linux yang sama dengan kartu S3 dari 20 tahun yang lalu. Dan konsol Linux dengan buffer bingkai resolusi tinggi pada kartu modern tidak dapat digunakan. :)
Satō Katsura
6
@ Kingofkech Itu sekitar 2400 bps. Beberapa dari kita benar-benar hidup selama bertahun-tahun dengan kecepatan itu. :)
Satō Katsura
14

Saya akan setuju secara naluriah dengan jawaban Satō Katsura; masuk akal. Namun, itu cukup mudah untuk diuji.

Saya diuji menulis sejuta baris ke layar, menulis (menambahkan) ke file, dan mengarahkan ke /dev/null. Saya menguji masing-masing pada gilirannya, kemudian melakukan lima ulangan. Ini adalah perintah yang saya gunakan.

$ 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)

Saya kemudian merencanakan total waktu di bawah ini.

alur waktu vs. keluaran

Seperti yang Anda lihat, anggapan Satō Katsura benar. Sesuai jawaban Satō Katsura, saya juga ragu bahwa faktor pembatasnya adalah output, jadi tidak mungkin pilihan output akan memiliki efek besar pada kecepatan keseluruhan skrip.

FWIW, jawaban asli saya memiliki kode yang berbeda, yang memiliki file yang ditambahkan dan /dev/nulldialihkan di dalam loop.

$ 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)

Seperti yang ditunjukkan oleh John Kugelman dalam komentar, ini menambah banyak biaya tambahan. Seperti pertanyaannya, ini sebenarnya bukan cara yang tepat untuk mengujinya, tetapi saya akan meninggalkannya di sini karena jelas menunjukkan biaya membuka kembali file berulang kali dari dalam skrip itu sendiri.

alur waktu vs. keluaran

Dalam hal ini, hasilnya terbalik.

Sparhawk
sumber
FWIW saya menambahkan tolok ukur cepat untuk jawaban saya. Khususnya, konsol Linux> 200 kali lebih lambat dari xterm, yang pada gilirannya ~ 3 kali lebih lambat dari /dev/null.
Satō Katsura
Anda juga harus menguji dengan beberapa pembatasan tingkat. Output OP adalah sekitar 200 baris / s.
muru
@muru Maksud Anda mencetak satu baris, tunggu 1/200 detik, lalu ulangi? Saya bisa mencoba, tetapi saya pikir itu akan menjadi hasil yang serupa, tetapi hanya butuh waktu lebih lama untuk sinyal untuk mengatasi kebisingan. Walaupun mungkin saya bisa mengurangi waktu tunggu sebelum analisis.
Sparhawk
@Sparhawk sesuatu seperti itu. Saya pikir pada level output itu, CPU akan punya banyak waktu untuk memperbarui tampilan tanpa memperlambat laju output. Ketika program tidak melakukan apa-apa selain memuntahkan garis tanpa jeda, buffer terminal akan terisi lebih cepat daripada tampilan yang dapat diperbarui dan menciptakan hambatan.
muru
3

Cara lain untuk mempercepat skrip adalah dengan menggunakan juru bahasa shell yang lebih cepat. Bandingkan kecepatan loop sibuk POSIX , jalankan di bawah bash v4.4 , ksh v93u + 20120801 , dan 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

    Keluaran:

    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

    Keluaran:

    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

    Keluaran:

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

Sebuah bagian dari perintah dalam bashdan kshyang backwardly kompatibel untuk semua perintah di dash. Sebuah bashskrip yang hanya menggunakan perintah di bagian itu harus bekerja dengan dash.

Beberapa bashskrip yang menggunakan fitur baru dapat dikonversi ke juru bahasa lain. Jika bashskrip sangat bergantung pada fitur yang lebih baru, mungkin tidak sepadan dengan itu - beberapabash fitur baru adalah peningkatan yang lebih mudah untuk dikodekan dan lebih efisien, (meskipun bashsecara umum lebih lambat), sehingga dashsetara, (yang mungkin melibatkan menjalankan beberapa perintah lain), akan lebih lambat.

Saat ragu, jalankan tes ...

agc
sumber
jadi untuk mempercepat skrip bash saya, saya perlu menulis ulang bash atau ksh?
Kingofkech
@ Kingofkech Mungkin kode yang Anda tulis untuk bash sudah benar ksh atau kode dasbor. Cobalah untuk mengubah juru bahasa saja.
bli