コンピューティングにおいて、パイプライン(データパイプラインとも呼ばれる)とは、直列に接続されたデータ処理要素の集合であり、ある要素の出力が次の要素の入力となる。パイプラインの要素は、並列処理または時間分割処理で実行されることが多い。要素間には、一定量のバッファ領域が挿入されることが多い。
パイプライン処理は、日常生活でよく使われる概念です。例えば、自動車工場の組立ラインでは、エンジンの取り付け、ボンネットの取り付け、ホイールの取り付けといった個々の作業は、それぞれ別の作業ステーションで行われることがよくあります。各ステーションは、それぞれ異なる車両に対して並行して作業を進めます。車両は一つの作業が完了すると、次のステーションへと移動します。作業完了に必要な時間のばらつきは、「バッファリング」(ステーション間のスペースに1台以上の車両を待機させる)や「ストール」(上流のステーションを一時的に停止させる)によって、次のステーションが利用可能になるまで対応できます。
仮に、自動車1台の組み立てに、それぞれ20分、10分、15分かかる3つの作業が必要だとします。もしこれら3つの作業を1つのステーションで行うと、工場は45分ごとに1台の自動車を生産することになります。一方、3つのステーションからなるパイプライン方式を採用すれば、最初の1台を45分で生産した後、20分ごとに1台の自動車を生産できるようになります。
この例が示すように、パイプライン処理はレイテンシ(つまり、1つのアイテムがシステム全体を通過するのにかかる合計時間)を短縮するわけではありません。しかし、システムのスループット(つまり、最初のアイテムが処理された後に新しいアイテムが処理される速度)は向上します。

コンピューティングにおいて、パイプラインまたはデータパイプライン[ 1 ]とは、直列に接続されたデータ処理要素の集合であり、ある要素の出力が次の要素の入力となる。パイプラインの要素は、並列または時間分割方式で実行されることが多い。要素間には、一定量のバッファストレージが挿入されることが多い。
コンピュータ関連のパイプラインには以下が含まれます。
パイプラインが冪等なステップで構成されている場合、最初の実行結果以降、これらのステップを再実行しても結果は変わりません。これは、信頼性と保守性の面で有利です。
パイプラインのスループットは、最も遅い要素のスループットを超えることはできないため、設計者は各ステージ間で作業とリソースを分割し、すべてのステージがタスクを完了するのに同じ時間を要するようにする必要があります。上記の自動車組立の例では、3つのタスクがそれぞれ20分、10分、15分ではなく15分で完了する場合、遅延時間は依然として45分ですが、新しい自動車は20分ごとではなく15分ごとに完成することになります。
理想的な状況では、すべての処理要素が同期しており、処理に同じ時間を要する場合、各要素は、前の要素によってリリースされたのとまったく同じタイミングで、単一のクロックサイクルで各要素に受信されます。このようにして、項目は水路の波のように、一定の速度でパイプラインを流れます。このような「波のパイプライン」[ 2 ]では、データ項目のストレージ以外に、ステージ間の同期やバッファリングは必要ありません。
より一般的には、処理時間が不規則な場合や、パイプラインの途中でアイテムが生成または破棄される場合、パイプラインの各ステージ間でバッファリングが必要になります。たとえば、画面にレンダリングする三角形を処理するグラフィックスパイプラインでは、各三角形の可視性をチェックする要素が、三角形が見えない場合はその三角形を破棄したり、部分的に隠れている場合は要素の2つ以上の三角形の断片を出力したりすることがあります。また、アプリケーションが最初のステージにアイテムを供給し、最後のステージの出力を消費する速度の不規則性に対応するためにも、バッファリングが必要です。
2つのステージ間のバッファは、適切な同期および信号ロジックを備えたハードウェアレジスタで構成できます。ステージAがレジスタにデータ項目を格納すると、次のステージBに「データ利用可能」信号を送信します。Bはそのデータを使用すると、Aに「データ受信」信号で応答します。ステージAは、次のデータ項目をレジスタに格納する前に、この信号を待って停止します。ステージBは、次の項目を処理する準備ができていても、ステージAからまだデータが提供されていない場合、「データ利用可能」信号を待って停止します。
要素の処理時間が変動する場合、パイプライン全体が停止し、その要素とそれ以前のすべての要素が入力バッファ内の項目を消費するのを待つ必要が生じることがよくあります。このようなパイプラインの停止頻度は、そのステージの入力バッファに複数の項目を格納するスペースを設けることで低減できます。このような複数項目バッファは、通常、先入れ先出し(FIFO)キューとして実装されます。キューが満杯になると、上流ステージが停止する必要が生じる場合もありますが、バッファスロットが増えるほど、停止頻度は減少します。キューイング理論を用いることで、処理時間の変動性と要求されるパフォーマンスに応じて、必要なバッファスロット数を算出できます。
ある段階の処理に他の段階よりもはるかに時間がかかり(またはかかる可能性があり)、かつ処理速度を上げることができない場合、設計者は単一の入力バッファと単一の出力バッファを備えた2つ以上の処理要素を用意して、そのタスクを並列に実行させることができます。各要素は現在の処理中のデータ項目の処理が完了すると、それを共通の出力バッファに送り、共通の入力バッファから次のデータ項目を取り出します。この「非線形」または「動的」パイプラインの概念は、2人以上のレジ係が1つの待機列から顧客に対応する店舗や銀行などでよく見られます。
アプリケーションによっては、ステージAによるアイテムYの処理が、パイプラインの後段ステージBによる前のアイテムXの処理結果または影響に依存する場合があります。その場合、アイテムXがステージBを通過するまで、ステージAはアイテムYを正しく処理できません。
この状況は、命令パイプラインで非常によく発生します。たとえば、Y が、以前の命令 X によって変更されたはずのレジスタの内容を読み取る算術命令であるとします。A を命令オペランドをフェッチするステージ、B を結果を指定されたレジスタに書き込むステージとします。ステージ A が命令 X がステージ B に到達する前に命令 Y を処理しようとすると、レジスタにはまだ古い値が残っている可能性があり、Y の効果が正しくなくなります。
このような競合を適切に処理するためには、パイプラインに競合を検出して適切な措置を講じるための追加の回路またはロジックを組み込む必要があります。そのための戦略としては、以下のようなものがあります。
データパイプラインを効果的に実装するには、利用可能なCPUコアに処理を割り当てるCPUスケジューリング戦略と、パイプラインの各ステージが操作するデータ構造の使用が必要です。たとえば、UNIX系のシステムでは、オペレーティングシステムが実装するパイプを使用して、さまざまなプロセスの標準入出力を接続するコマンドをパイプライン化できます。一部のオペレーティングシステムは、複数のプログラム実行をパイプラインに連結するためのUNIXライクな構文を提供しますが、パイプライン処理は真のパイプラインではなく、単純な逐次実行として実装されます。つまり、各プログラムの終了を待ってから次のプログラムを開始します。
低レベルのアプローチでは、オペレーティングシステムが提供するスレッドを利用してステージでの作業をスケジュールすることができます。スレッドプールベースの実装とステージごとに1つのスレッドを使用する実装の両方が有効であり、実際に存在します。[ 3 ]
協調型マルチタスクを利用する他の戦略も存在し、それらは複数の実行スレッドや追加のCPUコアを必要としません。例えば、コルーチンベースのフレームワークを用いたラウンドロビンスケジューラなどが挙げられます。この場合、各ステージは独自のコルーチンでインスタンス化され、ラウンドタスクの完了後にスケジューラに制御を戻します。このアプローチでは、プロセスの各ステージがタイムスライスを濫用しないように、各ステージを慎重に制御する必要があります。
パイプラインシステムは、一度に1つのバッチを実行するシステムよりも、一般的に多くのリソース(回路要素、処理ユニット、コンピュータメモリなど)を必要とします。これは、パイプラインシステムでは各ステージ間でリソースを共有できないこと、また、各要素間でバッファリングや追加の同期ロジックが必要になる場合があるためです。
さらに、個別の処理要素間でアイテムを転送すると、特に長いパイプラインの場合、レイテンシが増加する可能性があります。
パイプライン処理による複雑性の増加は、異なる項目の処理間に依存関係がある場合、特に推測とバックトラック戦略を用いてそれらを処理する場合、相当なものになる可能性がある。実際、複雑な命令セットに対してこの戦略を実装するコストは、RISCやVLIWといったコンピュータアーキテクチャを簡素化するための抜本的な提案を促してきた。コンパイラもまた、命令パイプラインのパフォーマンスを向上させるために、機械語命令を再配置するという作業を担ってきた。
近年、アプリケーションとその基盤となるハードウェアに対する要求は著しく高まっています。例えば、ビッグデータの量と多様性を考えると、データを1行ずつ処理する単一ノードのアプリケーションでパイプラインを構築することはもはや現実的ではありません。しかし、 Hadoopや最近ではApache Sparkなどのデータ分析エンジンの登場により、大規模なデータセットを複数の処理ノードに分散させることが可能になり、アプリケーションは以前考えられていたよりも数百倍も高い効率性を達成できるようになりました。その結果、現在では、このような分散処理を使用する中級レベルのPCでも、ビッグデータパイプラインの構築と実行に対応できるようになっています。[ 4 ]