2013年12月29日日曜日

zshのサブシェル実行がわからない

Software Design 1月号の第1特集第2章で、サブシェルについての解説があった。紙面のコマンド例ではプロンプトが%だったので、zshかなーと思って、サブシェルの解説で示されていたコマンド例と同じことをやってみたら、結果が異なった。結論から言うと、解説にも書いてあったけど、想定してるのはashまたはdashだった。あと、サブシェルの生成の契機がdashとzshだと違った。

紙面だと、dash で
  • $ (sleep 200 | sleep 200) &
したら、サブシェルが生成されていた。
zshで試すと、以下のようになっていた。
なぜ違うのだろうか。ていうか、そもそも、dashだと、パイプで繋いだプロセスがそれぞれ独立したプロセスとして起動されているのに対して、zshは、パイプの前にあるプロセスの子プロセスとしてパイプの後のプロセスが起動されている。

サブシェルを実行してその中でプロセスを二つ起動するのと、サブシェルを起動せずに、子プロセスとして二つ目のコマンドを実行するのだと、後者の方が高速な気がする。ただ、zshは結構大きいので、起動が遅い。なので、無駄にサブシェルを起動しないようにしているのではないかと思う。

実際に、シェルの起動と終了にかかる時間を測定してみた。dashもzshも、起動時に-cオプションでコマンドを渡せるので、*sh -c exitをtimeコマンドで10回測定した平均を計算した。ちなみに、どちらのコマンドもzshから起動している。dashから起動したら、また違う結果になると思う。

  • dash: 0.0026 s
  • bash: 0.0047 s
  • zsh: 0.0062 s
やっぱりdashが速い。

とここまできて、やっとA User's Guide to the Z-Shellの3.2.3項を読んだのだけど、
In zsh, all but the last portion of the `pipeline' thus created is run in different processes.
らしい。つまり、パイプの最右のコマンド以外は新しいプロセスを生成するらしい。で、() で括ったときにどうなるかというと、どうも、ps コマンドで眺めている感じだと、パイプの最右のプロセスが子プロセスとして生成されて、最右以外のプロセスは最右のプロセスの子プロセスとして生成されるっぽい。謎だ。

3.8.3項, 3.8.4項 あたりをちゃんと読まないと。

0 件のコメント:

コメントを投稿