シェルの&とwaitについて少し調べてみた
&はシェルにおいてバックグラウンド実行をするコマンド?です。 そして、複数のバックグランドジョブの終了を待つコマンドがwaitです。
つまり、
sleep 20 & sleep 10 & wait # 上2つのコマンド入力直後であれば20秒待機 # sleep 20 & sleep 10 & wait #1行にもできる
というコマンドは20秒sleepするジョブと10秒sleepするジョブをバックグランドで実行し、それらが終わるまで待つことになります。
今回はmanを見てもよくわからなかった2つの疑問を調べてみます。
疑問
- 1行に2つ書いた&によるバッググラウンド実行は、ハイパースレッドあるいはマルチコアで実行されるか
- waitによって完了を待つのは同じ親プロセスに属する&によるプロセスなのか
結論
- 1行に2つ書いた&によるバッググラウンド実行は、マルチコアで実行される
- waitによって完了を待つのは、同じ親プロセスに属するすべての&による子孫プロセス
環境
調査
疑問に対してそれぞれ調査して確認します。
マルチコアになるか
CPUに負荷をかけるためyesを2つバックグランドで実行します
$ yes > /dev/null & yes > /dev/null & [1] 2929 [2] 2930 $ jobs [1]- Running yes > /dev/null & [2]+ Running yes > /dev/null & $ top 略 %Cpu0 : 0.0/18.2 18[||||||||||||||||| ] %Cpu1 : 62.4/37.6 100[|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||] %Cpu2 : 0.0/1.1 1[| ] %Cpu3 : 64.0/36.0 100[|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||]
2つのCPUの利用率が100%になっているため、マルチコアで実行されるということがわかります。
バックグランドジョブの終了
$ kill %1 %2 $ jobs [1]- Terminated yes > /dev/null [2]+ Terminated yes > /dev/null
waitが待つプロセス
wait() This function waits for the first child to die. The return value is that of the wait(2) system call.
manの説明ではよくわからなかったので確認します。
叔父プロセス
親プロセスのfishでsleep 100
を実行し、その子プロセスのbashでさらにsleep 10
とsleep 5
を実行しました。
❯ sleep 100 & ❯ bash $ ps PID TTY TIME CMD 13 pts/1 00:00:06 fish 3248 pts/1 00:00:00 sleep 3311 pts/1 00:00:00 bash 3317 pts/1 00:00:00 ps $ sleep 10 & sleep 5 & pstree -p 13; wait [1] 3318 [2] 3319 fish(13)─┬─bash(3311)─┬─pstree(3320) │ ├─sleep(3318) │ └─sleep(3319) └─sleep(3248) # 10秒後 [1]- Done sleep 10 [2]+ Done sleep 5
上の挙動から親のfishで実行されたsleepは待たず、bashで実行された2つのsleepの実行を待っている事がわかります。
ワンライナーではない兄弟プロセス
$ sleep 20 & [1] 3354 $ sleep 5 & pstree -p 13; wait [2] 3355 fish(13)───bash(3311)─┬─pstree(3356) ├─sleep(3354) └─sleep(3355) # 約20秒後 [1]- Done sleep 20 [2]+ Done sleep 5
当然ですが、ワンライナーとか関係ないです。同じbashの子プロセスであればすべて待ちます。
甥プロセス
$ sh -c 'sleep 10' & sleep 5 & pstree -p 13; wait [1] 3358 [2] 3359 fish(13)───bash(3311)─┬─pstree(3360) ├─sh(3358)───sleep(3361) └─sleep(3359) # 10秒後 [1]- Done sh -c 'sleep 10' [2]+ Done sleep 5
同じ親を持つ子孫すべてのバックグラウンドジョブを待ちました。
まとめ
結論に書いたとおりですが、期待どおりの動作をしてくれました。 package.jsonのscripts内でコマンドを&で並列実行できるか確認したかったのが今回の調査の動機でした。
甥プロセスや叔父プロセスといった名詞があるかは知りません。