サブシェルを使用する場合のオーバーヘッドは何ですか?

サブシェルを使用する場合のオーバーヘッドは何ですか?

この質問が一般的すぎないことを願います。私はシェル スクリプトの初心者で、コンピューター アーキテクチャ/非スクリプト プログラミングのバックグラウンドを持っています。仕事で使用しているスクリプトでは、スクリプト全体をサブシェルで囲んで記述されることはめったにないことに気づきました。私が書いているスクリプトでは、サブシェルで囲める場合は、他のスクリプトを呼び出すスクリプトに影響しないようにするため、そうしています (念のため)。このアプローチにはオーバーヘッドが伴うため、これは一般的な方法ではないのでしょうか。オンラインでこれを見つけるのに苦労しています。

例:

#!/bin/bash
( #Start of subshell
echo "Some stuff here"
) #End of subshell

答え1

サブシェルにはオーバーヘッドがあります。

私のシステムでは、最小の fork-exec コスト (ファイルがコールドでないときにディスクからプログラムを実行する場合) は約で2ms、最小のフォーク コストは約です1ms

サブシェルの場合、ファイルを編集する必要がないため、フォークのコストだけを考えていますexec。サブシェルが適度に低く抑えられていれば、1ms人間が操作するプログラムでは はごくわずかです。 より速く発生する処理には人間は気付かないと思います(これは、最近のスクリプト言語インタープリタ (ここでは と Ruby について50ms話している) が起動するのにかかる時間で、最新のものでも程度かかります)。pythonrvmnodejs100ms

ただし、ループが追加されるため、たとえば、関数から何かを stdout に出力して親シェルが bashisms で処理する (または高速な外部プログラムを使用してバッチ全体を処理する) という、かなり一般的なバック アクションまたはパターンを置き換える必要が$()ある場合があります。returnprintf -v

bash 補完パッケージは、渡された変数名を介して返すことで、このサブシェルのコストを特に回避します。http://fvue.nl/wiki/Bash:_参照による変数の受け渡し


比較する

time for((i=0;i<10000;i++)); do echo "$(echo hello)"; done >/dev/null 

time for((i=0;i<10000;i++)); do echo hello; done >/dev/null 

forkシステムのオーバーヘッドがどの程度になるかを適切に見積もることができます。

答え2

PSkocik が提供する優れたコードを私のシステムで実行したところ、ほとんど結果は得られませんでした。

ただし、この例はまさにその通りです - ネイティブ コマンドとサブシェル コマンド:

MyPath="path/name.ext" 
# this takes forever
time for((i=0;i<10000;i++)); do echo "$(basename ${MyPath} )"; done >/dev/null 
#this is over 100x less time 
time for((i=0;i<10000;i++)); do echo "${MyPath##*/}"; done >/dev/null     

関連情報