Saya menjalankan skrip sederhana untuk menghasilkan file csv besar (10000000 baris) dengan 6 bidang di mana beberapa bidang berubah di setiap baris/baris, menggunakan sementara lingkaran. Mesin memiliki semua (32) CPU gratis, banyak RAM (~31 Gb) juga gratis.
Saya mengatur waktu skrip dengan perintah
/usr/bin/time -v bash script.01.sh
Setelah berlari selama sekitar 2 jam, saya mendapatkan statistik berikut:
Perintah diatur waktunya:“bash script.01.sh”
Waktu pengguna (detik):1195,14
Waktu sistem (detik):819,71
Persentase CPU yang didapat dari pekerjaan ini:27%
Waktu berlalu (jam dinding) (j:mm:dd atau m:ss):2:01:10
Rata-rata ukuran teks yang dibagikan (kbyte):0
Rata-rata ukuran data yang tidak dibagikan (kbyte ):0
Ukuran tumpukan rata-rata (kbyte):0
Ukuran total rata-rata (kbyte):0
Ukuran kumpulan penduduk maksimum (kbyte):4976
Ukuran kumpulan penduduk rata-rata (kbytes):):0
Kesalahan halaman utama (memerlukan I/O):0
Kesalahan halaman kecil (mengklaim kembali bingkai):3131983488
Sakelar konteks sukarela:22593141
Sakelar konteks tidak disengaja:10923348
Tukar:0
Masukan sistem berkas:0
Keluaran sistem berkas:2182920
Pesan soket terkirim:0
Pesan soket diterima:0
Sinyal terkirim:0
Ukuran halaman (byte):4096
Status keluar:0
Saya ingin tahu mengapa skrip saya hanya menggunakan 27% dari CPU? Disk IO tidak ada artinya sama sekali (lihat di output vmstat). Lalu apa yang menyebabkan pembatasan itu? Kode dalam skrip?
Berikut scriptnya:
#!/usr/bin/env bash
number=1
while [[ $number -lt 10000001 ]] ; do
fname="FirstName LastName $"
lname=""
email="[email protected]"
password="1234567890"
altemail="[email protected]"
mobile="9876543210"
echo "$fname,$lname,$email,$password,$altemail,$mobile" >> /opt/list.csv
number=$(expr $number + 1)
done
Jawaban yang Diterima:
Dengan menggunakan strace
, saya melihat garis itu
number=$(expr $number + 1)
menyebabkan percabangan, pencarian jalur, dan eksekusi expr
. (Saya menggunakan bash 4.2.45 di Ubuntu). Sistem file, disk, dan overhead proses menyebabkan bash hanya mendapatkan sekitar 28% dari CPU.
Ketika saya mengubah baris itu untuk hanya menggunakan operasi bawaan Shell
((number = number + 1))
bash menggunakan sekitar 98% CPU dan skrip berjalan dalam setengah jam. Ini menggunakan Celeron 1,5GHz satu-CPU.
Skrip apa adanya tidak melakukan apa pun yang berjalan secara paralel, jadi memiliki 32 CPU gratis tidak akan banyak membantu. Namun, Anda tentu dapat memparalelkannya dengan, misalnya, membaginya menjadi 10 loop 1 juta iterasi yang berjalan secara paralel, menulis ke 10 file berbeda, lalu menggunakan cat
untuk menggabungkannya.
Contoh program berikut telah ditambahkan oleh @Arthur2e5:
max=1000000 step=40000 tmp="$(mktemp -d)"
# Spawning. For loops make a bit more sense in a init-test-incr pattern.
for ((l = 0; l < max; l += step)); do (
for ((n = l + 1, end = (step + l > max ? max : step + l);
n <= end; n++)); do
# Putting all those things into the `buf` line gives you a 1.8x speedup.
fname="FirstName LastName \$"
lname=""
email="[email protected]"
password="1234567890"
altemail="[email protected]"
mobile="9876543210"
buf+="$fname,$lname,$email,$password,$altemail,$mobile"$'\n'
done
printf '%s\n' "$buf" > "$tmp/$l" ) &
done # spawning..
wait
# Merging. The filename order from globbing will be a mess,
# since we didn't format $l to some 0-prefixed numbers.
# Let's just do the loop again.
for ((l = 0; l < max; l += step)); do
printf '%s\n' "$(<"$tmp/$l")" >> /opt/list.csv
done # merging..
rm -rf -- "$tmp" # cleanup