東海道らぐ名古屋オフ(2017.10.7)発表内容より
Linuxにて
複数のコマンドを並列実行
(同時実行数の制限付き)
H.Hiro
Website: https://hhiro.net/
Twitter: @h_hiro_
このスライドについて
• 2017.10.7の東海道らぐ名古屋オフ
https://tokaidolug.connpass.com/event/67522/
にて発表した内容を、スライド化・加筆修正したものです
• 東海道らぐ名古屋オフの
当日その場で資料を
仕上げていて、スライドまで
作る余裕がなかったので
(このネタで話す構想自体は
あった)、当日はGoogle
ドキュメントに書いた内容で
話してました
目的
• Linuxにて、複数のプログラムを並列実行したい。
• 各プログラムは1スレッドで動く前提とする。
• このとき、同時実行数を制限したい。
すなわち、同時実行数を制限するという条件のもとで
なるべく処理を早く終わらせたい。
きっかけ
• 私は研究の仕事をしていて、「パラメータを変えて複数の
状況で計算をさせる」という実験を行うことが多い。
そうなると、複数コアがあるマシンで並列で動かしたい。
# 例
./program 1 10
./program 1 100
./program 2 10
./program 2 100
:
• 以前は、マシンのコア数に応じて手作業で
実験パターン数を分け、そのスクリプトを作っていたのだが、
流石に面倒になってきて、自動化しようと決心したのであった。
結論
• 実はxargsでだいたいのことはできてしまう
• 複雑なことをしたければparallel(GNU parallel)を
使うという手もある
最初に知った方法(wait利用)
waitというコマンドを知り、これを使って工夫することを考えた。
※wait:&を付けてバックグラウンド実行したコマンドがすべて
終わるまで待つ
まず&について簡単な確認
sleep 3; sleep 2; sleep 1
# ↑これだと逐次実行なので6秒待つ
sleep 3 & sleep 2 & sleep 1 &
# 後ろに&が付いているコマンドはバックグラウンド実行。
# この場合、何も待たない(実際には、待つということは
# 行われるがそれがバックグラウンドなので何の影響もない)
最初に知った方法(wait利用)
sleep 3 & sleep 2 & sleep 1; echo END
# これは、3秒待ってからENDが表示されるわけではない。
# 1秒しか待たない。
# 3秒待つのと2秒待つのはバックグラウンドなので。
sleep 3 & sleep 2 & sleep 1 & wait; echo END
# これだと、3秒待ってからENDが表示される。
これを使い、「コマンド実行回数をカウントし、所定の回数
コマンドを実行したら、全部終わるまでwaitする」ということを
していた。
最初に知った方法(wait利用)
プログラム例
running=0
for i in `seq 6 -1 1`; do # 6 5 4 3 2 1の順で実行
sleep $i
running=`expr $running + 1`
if [ $running -ge 3 ]; then
running=0
wait
fi
done
この場合、待つのは
6+5+…+1=21秒
ではなく、
6+3=9秒である。
6と5と4は並列、
3と2と1も並列。
最初に知った方法(wait利用)
この方法の問題点:
並列実行したものが全部終わらないと、次へ進めない
先程の例はこんな時間の使い方
しかし実際は、こう詰められるはず
コア1
コア2
コア3
wait終了 wait終了
コア1
コア2
コア3
6
5
4
3
2
1
16
25
34
xargsを使う方法
xargsを使う方法
つい最近知った。参考記事:
• xargs を使ってカジュアルに並列処理 - たごもりすメモ
http://tagomoris.hatenablog.com/entry/20110513/1305267021
• xargsは通常、「標準入力から受け取った内容を繋げた
コマンドを作り実行する」のに使うものなのだが
• その際に、コマンドを1つだけ作るのではなく複数作ると
いうオプション(「-L」や「-n」)があり、
• しかも、それを並列実行するオプション(「-P」)もある
※POSIX標準ではない。GNUにはある。
xargsを使う方法
• 普通、xargsは「標準入力から受け取った値を
コマンドの引数にまとめて渡す」。
seq 1 3 | xargs echo # "echo 1 2 3" と同等
• -Lオプションを付けると、標準入力から受け取った値を
何行ずつ区切って渡すかを指定できる。
それらは個別に順次実行される。
seq 1 3 | xargs -L 1 echo
# ↑"echo 1; echo 2; echo 3" と同等
seq 1 3 | xargs -L 1 sleep # 6秒待つ(1+2+3で)
• -Pオプションを付けると、その個数上限で並列実行する。
seq 1 3 | xargs -L 1 -P 3 sleep
# 待つのは3秒だけ
# (1秒待つ・2秒待つ・3秒待つのを並列実行している)
GNU parallelを使う方法
GNU parallelを使う方法
• さっきの記事で挙げられていて知った
• 参考記事
– コマンドを並列に実行するGNU parallelがとても便利
- りんごがでている
http://bicycle1885.hatenablog.com/entry/2014/08/10/143612
– GNU Parallel作者が書いたParallel:
The Command-Line Power Toolを読んだ
| Siguniang's Blog
https://siguniang.wordpress.com/2012/09/09/
notes-on-gnu-parallel-the-command-line-power-tool/
GNU parallelを使う方法
使い方
# -j 1 だとただの逐次実行
seq 4 3 10 | parallel -j 1 'echo sleep {} start;
sleep {}; echo sleep {} end: `date`'
【結果】
sleep 4 start
sleep 4 end: 2017年 10月 7日 土曜日 13:54:59 JST
sleep 7 start
sleep 7 end: 2017年 10月 7日 土曜日 13:55:07 JST
sleep 10 start
sleep 10 end: 2017年 10月 7日 土曜日 13:55:17 JST
GNU parallelを使う方法
使い方
# -j 3 で3つすべてを並列に実行
seq 4 3 10 | parallel -j 3 'echo sleep {} start;
sleep {}; echo sleep {} end: `date`'
【結果】
sleep 4 start
sleep 4 end: 2017年 10月 7日 土曜日 13:54:23 JST
sleep 7 start
sleep 7 end: 2017年 10月 7日 土曜日 13:54:26 JST
sleep 10 start
sleep 10 end: 2017年 10月 7日 土曜日 13:54:29 JST
GNU parallelを使う方法
使い方
# -j 2 だと、「4秒待つ」と「7秒待つ」のどちらか(=前者)が
# 終わってから、「10秒待つ」が実行される
seq 4 3 10 | parallel -j 2 'echo sleep {} start;
sleep {}; echo sleep {} end: `date`'
【結果】
sleep 4 start
sleep 4 end: 2017年 10月 7日 土曜日 13:54:39 JST
sleep 7 start
sleep 7 end: 2017年 10月 7日 土曜日 13:54:42 JST
sleep 10 start
sleep 10 end: 2017年 10月 7日 土曜日 13:54:49 JST
GNU parallelを使う方法
使い方
# 括弧やリダイレクトがそのまま書けるのもポイント高いところ
seq 4 3 10 | parallel -j 1 '(echo sleep {} start;
sleep {}; echo sleep {} end: `date`) > log{}.txt'
これを実行すると、先程の内容が、それぞれ
log4.txtとlog7.txtとlog10.txtに保存される
おまけ:
全プログラムをなるべく早く
終わらせるためのポイント
おまけ
• 終了までの時間を早くしたければ、基本的には「実行時間が
長いものから実行する」のがよい。
ただ、完全に最適な実行時間にしたければ、全組み合わせを
試すのに相当する程度の時間はかかる。
• 同時並列数を固定とした場合、
– (すべての並び順を考慮して)終了までの時間を
最適化した場合の時間と、
– 単に「実行時間が長いものから実行する」とした場合での
終了までの時間を比べると、
後者は前者の(1 + 1/3)倍以内で収まることが知られている。
Graham, R. L. (1969). "Bounds on multiprocessing timing anomalies".
SIAM journal on Applied Mathematics, 17(2), 416-429.

Linuxにて複数のコマンドを並列実行(同時実行数の制限付き)