Saya sedang menguji kecepatan Bash dan Python dengan menjalankan loop 1 miliar kali.
$ cat python.py
#!/bin/python
# python v3.5
i=0;
while i<=1000000000:
i=i+1;
Kode bash:
$ cat bash2.sh
#!/bin/bash
# bash v4.3
i=0
while [[ $i -le 1000000000 ]]
do
let i++
done
Menggunakan time
perintah saya menemukan bahwa kode Python hanya membutuhkan waktu 48 detik untuk menyelesaikannya sementara kode Bash mengambil lebih dari 1 jam sebelum saya membunuh skrip.
Kenapa begitu? Saya berharap bahwa Bash akan lebih cepat. Apakah ada yang salah dengan skrip saya atau Bash jauh lebih lambat dengan skrip ini?
echo echo hello >> $0
, dan jalankan.Jawaban:
Ini adalah bug yang dikenal di bash; lihat halaman manual dan cari "BUGS":
;)
Untuk primer yang bagus tentang perbedaan konseptual antara skrip shell dan bahasa pemrograman lainnya, saya sangat merekomendasikan membaca:
Kutipan yang paling relevan:
Jangan gunakan loop besar dalam skrip shell.
sumber
Loop shell lambat dan bash adalah yang paling lambat. Kerang tidak dimaksudkan untuk melakukan pekerjaan berat di loop. Shell dimaksudkan untuk meluncurkan beberapa proses eksternal dan dioptimalkan pada kumpulan data.
Ngomong-ngomong, saya penasaran bagaimana perbandingan shell jadi saya membuat sedikit patokan:
( Detail:
)
Hasil (disingkat) (waktu per iterasi) adalah:
Dari hasil:
Jika Anda ingin loop shell sedikit lebih cepat, maka jika Anda memiliki
[[
sintaks dan Anda ingin loop shell cepat, Anda berada di shell maju dan Anda juga memiliki C-seperti untuk loop. Gunakan C suka untuk loop, lalu. Mereka bisa sekitar 2 kali lebih cepat dariwhile [
-Loop di shell yang sama.for (
loop tercepat sekitar 2,7 μs per iterasiwhile [
loop tercepat sekitar 5,8 μs per iterasiC untuk loop dapat menjadi 3-4 desimal dari besarnya lebih cepat. (Saya mendengar cinta Torvalds C).
C untuk loop yang dioptimalkan adalah 56500 kali lebih cepat dari
while [
loop bash (loop shell paling lambat) dan 6750 kali lebih cepat darifor (
loop ksh (loop shell tercepat).Sekali lagi, lambatnya shell seharusnya tidak terlalu menjadi masalah, karena pola khas shell adalah untuk membongkar beberapa proses program eksternal yang dioptimalkan.
Dengan pola ini, kerang sering membuatnya jauh lebih mudah untuk menulis skrip dengan kinerja lebih unggul daripada skrip python (terakhir kali saya memeriksa, membuat proses pipa dengan python agak canggung).
Hal lain yang perlu dipertimbangkan adalah waktu startup.
membutuhkan 30 hingga 40 ms pada PC saya sedangkan cangkang memakan waktu sekitar 3ms. Jika Anda meluncurkan banyak skrip, ini dengan cepat bertambah dan Anda dapat melakukan sangat banyak dalam 27-37 ms ekstra yang dibutuhkan python hanya untuk memulai. Skrip kecil dapat diselesaikan beberapa kali dalam jangka waktu tersebut.
(NodeJs mungkin runtime scripting terburuk di departemen ini karena dibutuhkan sekitar 100 ms hanya untuk memulai (meskipun begitu sudah dimulai, Anda akan sulit sekali menemukan pemain yang lebih baik di antara bahasa scripting)).
sumber
ksh88
, AT & Tksh93
,pdksh
,mksh
...) karena ada cukup banyak variasi di antara mereka. Sebabbash
, Anda mungkin ingin menentukan versi. Ini membuat beberapa kemajuan akhir-akhir ini (yang berlaku juga untuk shell lain).from subprocess import *; p1=Popen(['echo', 'something'], stdout=PIPE); p2 = Popen(['grep', 'pattern'], stdin=p1.stdout, stdout=PIPE); Popen(['wc', '-c'], stdin=PIPE)
. Ini memang canggung, tetapi seharusnya tidak sulit untuk mengkodekanpipeline
fungsi yang melakukan ini untuk Anda untuk sejumlah proses, yang menghasilkanpipeline(['echo', 'something'], ['grep', 'patter'], ['wc', '-c'])
.Saya melakukan sedikit pengujian, dan pada sistem saya menjalankan yang berikut - tidak ada yang membuat urutan percepatan yang diperlukan untuk menjadi kompetitif, tetapi Anda dapat membuatnya lebih cepat:
Tes 1: 18.233s
test2: 20.45s
test3: 17.64s
test4: 26.69s
test5: 12.79s
Bagian penting dalam yang terakhir ini adalah ekspor LC_ALL = C. Saya telah menemukan bahwa banyak operasi bash berakhir secara signifikan lebih cepat jika ini digunakan, khususnya fungsi regex apa pun. Itu juga memperlihatkan sintaks yang tidak didokumentasikan untuk menggunakan {} dan: sebagai no-op.
sumber
[[
jauh lebih cepat daripada[
. Saya tidak tahu LC_ALL = C (BTW Anda tidak perlu mengekspornya) membuat perbedaan.[[
adalah bash builtin, dan[
benar-benar/bin/[
, yang sama dengan/bin/test
- program eksternal. Itu sebabnya thay lebih lambat.[
adalah builtin di semua shell umum (cobatype [
). Program eksternal sebagian besar tidak digunakan sekarang.Sebuah shell efisien jika Anda menggunakannya untuk apa yang telah dirancang untuknya (meskipun efisiensi jarang apa yang Anda cari dalam shell).
Shell adalah interpreter baris perintah, ia dirancang untuk menjalankan perintah dan meminta mereka bekerja sama untuk suatu tugas.
Jika Anda ingin menghitung sampai 1000000000, Anda memanggil (satu) perintah untuk menghitung, seperti
seq
,bc
,awk
ataupython
/perl
... Menjalankan 1000000000[[...]]
perintah dan 1000000000let
perintah pasti akan sangat tidak efisien, terutama denganbash
yang merupakan shell yang paling lambat dari semua.Dalam hal itu, shell akan jauh lebih cepat:
Meskipun tentu saja, sebagian besar pekerjaan dilakukan oleh perintah yang diminta shell, sebagaimana mestinya.
Sekarang, Anda tentu saja dapat melakukan hal yang sama dengan
python
:Tapi itu tidak benar-benar bagaimana Anda akan melakukan hal-hal
python
sepertipython
itu terutama bahasa pemrograman, bukan penerjemah baris perintah.Perhatikan bahwa Anda dapat melakukan:
Tapi,
python
sebenarnya akan memanggil shell untuk menafsirkan baris perintah itu!sumber
Jawaban: Bash jauh lebih lambat daripada Python.
Salah satu contoh kecil adalah dalam kinerja posting blog beberapa bahasa .
sumber
Tidak ada yang salah (kecuali harapan Anda) karena python sangat cepat untuk bahasa yang tidak dikompilasi, lihat https://wiki.python.org/moin/PythonSpeed
sumber
Selain komentar, Anda bisa mengoptimalkan kode kecil yang , misalnya
Kode ini seharusnya memakan waktu lebih sedikit .
Tapi jelas tidak cukup cepat untuk bisa digunakan.
sumber
Saya perhatikan perbedaan dramatis dalam bash dari penggunaan ekspresi "sementara" dan "hingga" yang secara logika setara:
Bukannya itu benar-benar memiliki relevansi yang luar biasa dengan pertanyaan, selain itu mungkin kadang-kadang perbedaan kecil membuat perbedaan besar, meskipun kami berharap mereka akan setara.
sumber
((i==900000))
.=
untuk tugas. Ini akan segera kembali benar. Tidak akan ada loop yang terjadi.