概要
一つ一つで見るとCPU負荷がそれほどじゃないコマンドを一気にバルク実行(並列実行)したいですよね?
大量のコマンドをリミット付けてバルク実行させますよね?
並列実行コントローラシェルスクリプトです。
投稿するには規模が大きいかな?とか思いましたがネットにサンプルないので必要かなと…
Cygwinでも動きます(たぶん)
コントローラソース
ディレクトリ配下のファイルをfindし実行用スクリプトに順次渡してバルク実行しています。
このソースは関数化してないので構造の解析把握が必要になります。
バルク実行は取り扱いがあれなので、内部動作は十分知っておいた方が良いと思います。
bulk_kicker.sh
# !/bin/bash
if [ $# -ne 1 ]; then
echo "usage: " 1>&2
echo " ${0##*/} /path/name" 1>&2
exit 1
fi
CheckDir=$1
ReturnNo=0
ExitCheckFileName="exists_loop_${0##*/}.flg"
# 並列同時実行数 初期値
# カレントディレクトリの config に多重数を書き込んで変更する
BulkLimit=6
BulkLimitControlFile="bulk_limit_${0##*/}.cfg"
# 終了判定用ファイル作成、存在しなくなれば終了
# ※ 緊急時にこのファイルを削除するとループ終了
echo 'if not exists this file, next step exit script.' > $ExitCheckFileName
echo "**** start ****"
# ファイルリスト配列作成
# ※ ファイルリストをループする場合
echo "[$CheckDir]"
pushd $CheckDir >& /dev/null
unset ArrayFiles;
for LINE in `find ./ -name "*" | sort`; do
if [ -s $LINE ]; then
ArrayFiles+=($LINE)
fi
done
unset LINE;
popd >& /dev/null
unset pids
for el in ${ArrayFiles[@]}; do
if [ ! -e $ExitCheckFileName ]; then
# 終了判定用ファイル、存在しなくなれば終了
break;
fi
# 多重起動制御数取り込み
if [ ! -e $BulkLimitControlFile ]; then
echo $BulkLimit > $BulkLimitControlFile
else
BulkLimit=`head -n 1 $BulkLimitControlFile`
fi
while true
do
# 現多重数取得
pnum=0
unset switchPids
for pid in ${pids[@]}; do
GetStatus=`ps -p $pid | grep $pid`
if [ "$GetStatus" != "" ]; then
switchPids+=($pid)
let pnum++
fi
done
unset pids
pids=(${switchPids[@]})
if [ $pnum -lt $BulkLimit ]; then
break;
fi
sleep 1
done
# 多重起動するshを & 付きで実行
dno=`printf "%04d" ${#pids[*]}`
echo "[`date '+%Y/%m/%d %T'`] "$dno 'sh ./bulker.sh' $CheckDir/$el
eval 'sh ./bulker.sh' $CheckDir/$el &
pids+=($!)
# for pid in ${pids[@]}; do
# echo "pids $pid"
# done
done
# 走っているプロセスの終了を待つ
while true
do
# 現多重数取得
unset switchPids
for pid in ${pids[@]}; do
GetStatus=`ps -p $pid | grep $pid`
# GetId=`ps | grep $pid | awk '{print $1}'`
if [ "$GetStatus" != "" ]; then
switchPids+=($pid)
fi
done
unset pids
pids=(${switchPids[@]})
if [ "${#pids[*]}" == "0" ]; then
break;
fi
sleep 0.5
done
# dno=`printf "%04d" ${#pids[*]}`
# echo "pids $dno"
echo "**** end ****"
exit $ReturnNo
呼ばれる側(参考)
bulker.sh
# !/bin/bash
# バルク実行テスト用なので適当にsleep入れてます
# 引数のファイルサイズをechoするだけのスクリプトです
path=$1
fsize=`wc -c $1 | awk '{print $1}'`
fsize=`printf "%10d" $fsize`
sleep 1
echo "[`date '+%Y/%m/%d %T'`] $fsize $path"
sleep 1
実行結果
相対パスを指定してますが、シェルを使う場合は絶対パスが良いです。
ekaneko@bibian ~/work/bulker % bash bulk_kicker.sh ../
**** start ****
[../]
[2014/05/23 15:34:17] 0000 sh ./bulker.sh ..//./
wc: ..//./: ディレクトリです
[2014/05/23 15:34:17] 0001 sh ./bulker.sh ..//./arg_check.sh
[2014/05/23 15:34:17] 0002 sh ./bulker.sh ..//./bulker
wc: ..//./bulker: ディレクトリです
[2014/05/23 15:34:17] 0003 sh ./bulker.sh ..//./bulker/bulk_kicker.sh
[2014/05/23 15:34:17] 0004 sh ./bulker.sh ..//./bulker/bulk_limit_bulk_kicker.sh.cfg
[2014/05/23 15:34:17] 0005 sh ./bulker.sh ..//./bulker/bulker.sh
[2014/05/23 15:34:18] 0 ..//./
[2014/05/23 15:34:18] 87 ..//./arg_check.sh
[2014/05/23 15:34:18] 0 ..//./bulker
[2014/05/23 15:34:18] 2561 ..//./bulker/bulk_kicker.sh
[2014/05/23 15:34:18] 2 ..//./bulker/bulk_limit_bulk_kicker.sh.cfg
[2014/05/23 15:34:18] 145 ..//./bulker/bulker.sh
[2014/05/23 15:34:20] 0000 sh ./bulker.sh ..//./bulker/exists_loop_bulk_kicker.sh.flg
[2014/05/23 15:34:20] 0001 sh ./bulker.sh ..//./mysql
wc: ..//./mysql: ディレクトリです
[2014/05/23 15:34:20] 0002 sh ./bulker.sh ..//./mysql/mymysql.sh
[2014/05/23 15:34:20] 0003 sh ./bulker.sh ..//./mysql/mymysql_test.sh
[2014/05/23 15:34:21] 48 ..//./bulker/exists_loop_bulk_kicker.sh.flg
[2014/05/23 15:34:21] 0 ..//./mysql
[2014/05/23 15:34:21] 1681 ..//./mysql/mymysql.sh
[2014/05/23 15:34:21] 379 ..//./mysql/mymysql_test.sh
**** end ****
ekaneko@bibian ~/work/bulker %
解説
簡単に…
実行時に2つファイルを生成します(存在しない場合)
-
bulk_limit_bulk_kicker.sh.cfg
-
exists_loop_bulk_kicker.sh.flg
-
limitはバルク数(同時実行数)です。実行中に変更も効きますけどタイミング悪いと飛びます。
こんな感じに使います
% echo 3 > bulk_limit_bulk_kicker.sh.cfg
- exists_loop は緊急終了トリガーファイルです。消すとループを抜けるので移行の処理を行いません。
こんな感じに使います。
% rm exists_loop_bulk_kicker.sh.flg