&はシェルにおいてバックグラウンド実行をするコマンド?です。
そして、複数のバックグランドジョブの終了を待つコマンドがwaitです。
つまり、
sleep 20 &
sleep 10 &
wait
というコマンドは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)
[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)
[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)
[1]- Done sh -c 'sleep 10'
[2]+ Done sleep 5
同じ親を持つ子孫すべてのバックグラウンドジョブを待ちました。
まとめ
結論に書いたとおりですが、期待どおりの動作をしてくれました。
package.jsonのscripts内でコマンドを&で並列実行できるか確認したかったのが今回の調査の動機でした。
甥プロセスや叔父プロセスといった名詞があるかは知りません。