簡単なスクリプトを実行して、6つのフィールドを持つ大きな(10000000行)csvファイルを生成しました。このファイルでは、 while を使用して、各行/行でいくつかのフィールドが変更されています。 ループ。マシンにはすべての(32)CPUが空いていて、多くのRAM(〜31 Gb)も空いていました。
コマンドでスクリプトの時間を計りました
/ usr / bin / time -v bash script.01.sh
約2時間実行した後、次の統計を取得しました:
計時されるコマンド:“ bash script.01.sh”
ユーザー時間(秒):1195.14
システム時間(秒):819.71
このジョブが取得したCPUの割合:27%
経過(ウォールクロック)時間(h:mm:ssまたはm:ss):2:01:10
平均共有テキストサイズ(kバイト):0
平均非共有データサイズ(kバイト) ):0
平均スタックサイズ(kbytes):0
平均合計サイズ(kbytes):0
最大常駐セットサイズ(kbytes):4976
平均常駐セットサイズ(kbytes) ):0
メジャー(I / Oが必要)ページ障害:0
マイナー(フレームの再利用)ページ障害:3131983488
自発的コンテキストスイッチ:22593141
非自発的コンテキストスイッチ:10923348
スワップ:0
ファイルシステム入力:0
ファイルシステム出力:2182920
送信されたソケットメッセージ:0
受信されたソケットメッセージ:0
配信された信号: 0
ページサイズ(バイト):4096
終了ステータス:0
スクリプトがCPUの27%しか使用しなかった理由を知りたいのですが。ディスクIOはまったく何もありませんでした(vmstat出力で見ました)。では、何が制限を引き起こしたのでしょうか?スクリプト内のコード?
スクリプトは次のとおりです:
#!/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
承認された回答:
strace
を使用する 、私はその線を見ました
number=$(expr $number + 1)
expr
のフォーク、パス検索、およびexecを発生させます 。 (私はUbuntuでbash 4.2.45を使用しています)。そのファイルシステム、ディスク、およびプロセスのオーバーヘッドにより、bashはCPUの約28%しか取得できませんでした。
その行をシェルビルトイン操作のみを使用するように変更したとき
((number = number + 1))
bashはCPUの約98%を使用し、スクリプトは30分で実行されました。これはシングルCPUの1.5GHzCeleronでした。
スクリプトはそのままでは何も並行して実行されないため、32個の空きCPUがあるとあまり役に立ちません。ただし、たとえば、並列で実行される10個の100万回の反復ループに分割し、10個の異なるファイルに書き込んでから、cat
を使用することで、確実に並列化できます。 それらを組み合わせる。
次のサンプルプログラムは@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