コマンドや bash 内の関数を並列実行(bash を使用)
概要:コマンドや bash 内の関数を並列実行するための bash スクリプト.
xargs の「-P」(並列実行の最大プロセス数の指定)を使用する.
並行実行での性能確認の実験(CSV ファイルインポート,テーブルのコピー,SQL 問い合わせ)で共通に使う「決まり文句」でもある.
計測中のプロセッサ,ストレージの利用状況の確認は,dstat(システム計測ソフト)のページで説明している.
使い方
- TODOLIST は,並列実行させたいコマンド,あるいは「taskほにゃらら <引数>」を1行に1つずつ書く
- NUM_CONCURRENT は,並列度(同時に実行するプロセス数)
- 次の手順で実行開始
# ファイル名 concurrent.sh で保存したのち,実行可能にして実行
chmod 755 concurrent.sh
bash ./concurrent.sh
bash スクリプト
#!/bin/bash
# concurrent execution of tasks
# さまざまな種類のタスクがあるとする
function task00() {
# 引数:表示の繰り返し回数(1以上の整数)
for i in `seq 1 $1`; do
echo '0'
sleep 1
done
}
function task01() {
# 引数:表示の繰り返し回数(1以上の整数)
for i in `seq 1 $1`; do
echo '1'
sleep 1
done
}
function task02() {
# 引数:表示の繰り返し回数(1以上の整数)
for i in `seq 1 $1`; do
echo '2'
sleep 1
done
}
function task03() {
# 引数:表示の繰り返し回数(1以上の整数)
for i in `seq 1 $1`; do
echo '3'
sleep 1
done
}
function task04() {
# 引数:表示の繰り返し回数(1以上の整数)
for i in `seq 1 $1`; do
echo '4'
sleep 1
done
}
#########################################################################
# キャッシュのクリア(PageCache, dentries and inodes)
function cache_clear() {
/usr/bin/sync
/usr/bin/sync
/usr/bin/sync
/usr/bin/sync
/usr/bin/sync
sleep 3
sudo sysctl -w vm.drop_caches=3 > /dev/null
echo 3 | sudo tee -a /proc/sys/vm/drop_caches > /dev/null
return
}
# 現在時刻(あとで引き算しやすいように unixtime)
function current_time() {
echo `date +%s.%N`
return
}
#########################################################################
# TODOLIST は,実行させたいコマンド,あるいは「taskほにゃらら <引数>」
TODOLIST=$(cat <<EOD
task01 10
task02 10
task03 10
task04 10
EOD
)
# 並列度
NUM_CONCURRENT=3
#########################################################################
# TODOLIST の記載を,指定された並列度で実行する.
# この先は決まり文句(変更不要)
# 引数が1個のときは,行番号の指定である.TODOLIST のその行番号の1行を実行する.
if [ $# == 1 ]; then
# echo "$TODOLIST" のように「"」を付けると改行が保たれる
eval $(echo "$TODOLIST" | sed -n ${1}p)
exit
fi
# 引数なしで実行するとき,
# seq 1 $(echo "$TODOLIST" | wc -l) は,1から TODOLIST の行数までの整数を順に生成する.
# 使うときは chmod 755 で実行可能にしておくこと.
seq 1 $(echo "$TODOLIST" | wc -l) | xargs -L 1 -P ${NUM_CONCURRENT} bash "$0"
仕組みの説明
- 引数なしで実行すると,「seq 1 <TODOLIST の行数>」が行番号を生成し,xargs が「bash "$0" <行番号>」を並列度 NUM_CONCURRENT で起動する.
- 引数付き(行番号)で起動された側は,TODOLIST の該当する1行を sed で取り出し,eval で実行する.
- つまり,同じスクリプトが「親(振り分け役)」と「子(1行の実行役)」の2つの役割を持つ.
考察ポイント
- NUM_CONCURRENT を 1, 2, 3, 4 と変えたとき,全体の終了までの時間はどう変わるか.
- タスク数(TODOLIST の行数)が並列度で割り切れないとき,最後の方でプロセッサが遊ぶ時間ができることを確認する.
- sleep のような待ち中心のタスクと,計算やストレージアクセス中心のタスクとで,並列化の効果はどう違うか.