読者です 読者をやめる 読者になる 読者になる

パイプで並列処理

Linux

はじめに

Software Design 2012年8月号」の「開眼シェルスクリプト」の焼き直し。
Webにあるので一読することを勧める。
https://blog.ueda.asia/?page_id=4520

パイプにつなげたコマンドは...

並列稼働する(複数のCPUをなるたけ休まず働かせようとする
複数のCPUが、パイプで連結された各コマンドの動作/停止を高速に切り替えることで、
加工データをバケツリレー形式で前から後ろへ送っていく。

並列化されていることは、以下のようにして確認できる。

● timeコマンドの結果、「user > real」となっている(1個のCPUでは「実際に掛かった待ち時間」よりもCPU時間の方が長くなることはない、
基本的に「user + sys = real」
※正確な処理時間を測る場合は、繰り返し計測を行い、統計情報(平均値とばらつきの傾向等)を求める必要がある

● topコマンドの結果、対象コマンド(パイプより連結された複数のコマンド)のCPU使用率が100%を超えている
(例えば、計150%であれば、1.5個分のCPUを使用しているといえる

ちなみに、より多くのコマンドをつないでも、パフォーマンスは落ちるどころか、むしろ改善する(CPUが多いほど顕著
CPUの数に応じて効果の度合いは変動するものの、コマンドを細かく分割するほうが、時間当たりの処理量が増える。

並列化の限界

パイプでつながれたコマンドが、各CPUを休まず働かせることができるのは、データが滞りなく流れている時のみ。
言い換えると、次の2つの状況は...
● パイプ前のコマンドがデータを送ってこない場合
● パイプ後のコマンドがデータの受け取りに手間取っている場合

事例として次のようなものが挙げられる。

● 負荷にばらつきがある場合、一番負荷の高いコマンドの処理時間以上に処理が早く終わることはない
例えば、grepの検索結果をawkで処理する(grepの処理するデータ量がawkの処理するデータ量よりも多い)場合、
grep側の処理が終わるのを待つ必要がある。
ただ、1個のCPUであっても、細かい時間間隔で各コマンドの動作/停止が切り替わることに変わりはないため、
処理を分割しパイプにつなげることで、負荷の高いコマンドの終了を待っている間にCPUを効率的に使うことはできる

● データをブロックするコマンドがある場合、そのコマンドがボトルネックになる
例えば、sortコマンドは全データを読み込まないと結果を出力できないため、
sortコマンドをパイプでつなげた場合、sortが終わるまで後続の処理は実行されない
対応としては、sortコマンドの位置をできるだけ後ろに回す、またはsortコマンドの処理するデータ量を減らすことで処理効率を上げる