bashで並列化

bash

この記事は、株式会社カオナビ Advent Calendar 2021の8日目の記事です。

こんにちわ。貼り絵職人と申します。

最近はPython, Rubyなどが使われてるシェルスクリプトですが

古のインターネットおじさんなで提供はbashにしようかとおもいます。

bashで並列化をするときの方法

今回のお話はbashを並列する方法です。プログラミング、特にサーバーサイドの処理はシングルスレッドが多いですが、Native開発、サーバー側のコアな部分での大規模データの分散処理など

そういう時に並列処理を使います

bashで並列処理をするにはおおまかに2つの方法があります

  • xargs方法
  • &方法

それぞれ特徴があります

実装方法は違えどどちらも可能です(若干ですが可読性は&のほうがよい)

xargs

  • ワンライナーで簡素にできる
  • 高速である

などの特徴があります

xargsで利用する並列の例

たとえばこういうシェルスクリプトがあります

#!/bin/zsh

echo "catch $1"

# 実行時間 待機
sleep 1

echo "hello $1"

単に1秒待って引数を表示させるshellです。これを連続で実行しましょう。

$seq 5 | xargs -I{} sh ./echo.sh {}

seqで1〜5の数値をパイプから渡し、xargs の -Iオプションで変数{}に渡し、echo.shで実行します

直列実行だと、1~5と順番に動作します

引数が1~5なので短く感じますがこれが1万、10万になると時間が膨大になります

なので、プロセスを並列する-Pオプションを入れてみましょう

$seq 5 | xargs -P5 -I{} sh ./echo.sh {}

-Iは変数として{}を宣言します。

-Pオプションは並列させるプロセス数となります。これで実行してみましょう

5プロセス同時に実行しているので1秒待ってhelloが出る形です。

実行時間の短縮にもなります

xargsでちょっと複雑な並列処理

少し複雑な処理をしてみましょう

例えば以下のような要件があります

①mysqlサーバーが7台あり、それを並列実行したいです

②さらにmysqlにわたすパラメータは複数となります

サーバーは7台あると見込んで作ってみましょう

echo.shに複数パラメータが渡せるように修正しましょう

#!/bin/bash

echo "catch $1"

# 実行時間 待機
sleep 1


echo "hello $1:$2"
# 実行時間 待機
sleep 1

echo "var $1:$4"
# 実行時間 待機
sleep 1

echo "ここでmysqlサーバーのクエリ実行 $1: $2: $3: $4"

複数のmysql

(mysqlサーバーを立てたり、どういうテーブルで実行するかなど詳細は割愛します)

とりいそぎ、検索結果をhost.txt という形に変換しておきます

# host=`MYSQL_PWD="password" mysql -uroot -hroot common -N -s -e "select * from host"`
# ↑の検索結果としてhost.txtを代替
#$ cat host.txt 
host01
host02
host03
host04
host05
host06
host07

array型に変換してどの様になってるか確かめてみましょう

#$ array_text=(`cat host.txt`)| echo ${array_text[@]}
host01 host02 host03 host04 host05 host06 host07

これを並列実行してみます

array_text=(`cat host.txt`)| echo ${array_text[@]} | xargs -L1 -P5 -I{} bash -c "./echo2.sh {} aaa bbb ccc"

array_textはhost.txtを配列化します

bashではecho ${array_text[@]}することで

  • 変数の宣言
  • xargsにわたす

役割があります。xargsのオプションは以下になります

-Ixargsで利用する変数
-necho2.shにわたす引数の数
-P並列するプロセス数
bash -cbashとして実行

実行可能できました。ワンライナーでスッキリしますが、可読性は悪いですね

&

もう一つの方法として実行に&を後ろにつけてwaitを入れることで並列化ができます

メリットとしては「可読性が良い」という点があります

xargsのオプションをしらないエンジニアでもなんとなくわかりますね.

見やすくするため、forで回すシェルスクリプトを作ります

#!/bin/bash

array_text=(`cat host.txt`)

#並列処理
for host in $(echo "${array_text[@]}"); do
  bash -c "./echo2 ${host} aaa bbb ccc" &
done
wait

結論

実際Blogを書くまで実は「xargsは複雑な処理はできない」と思っておりましたが、実際検証してみるとどちらも並列化できることがわかりました。bashの世界は奥が深い

bash
スポンサーリンク
Harieshokuninをフォローする
できるだけ楽するハック
タイトルとURLをコピーしました