糸と繊維の違いは何ですか?ruby のファイバーについて聞いたことがありますし、他の言語でも利用できると聞いたことがあります。スレッドとファイバーの違いを簡単な言葉で説明してもらえますか?
9 に答える
最も簡単に言えば、スレッドは一般にプリエンプティブであると見なされますが(オペレーティングシステムによっては、これが常に当てはまるとは限りません)、ファイバーは軽量で協調的なスレッドであると見なされます。どちらも、アプリケーションの個別の実行パスです。
スレッドの場合:現在の実行パスはいつでも中断またはプリエンプションされる可能性があります(注:このステートメントは一般化されたものであり、OS /スレッドパッケージなどによっては常に当てはまるとは限りません)。これは、スレッドの場合、データのチャンクを更新している途中で1つのスレッドが停止し、データの整合性が不良または不完全な状態のままになる可能性があるため、データの整合性が大きな問題になることを意味します。これは、オペレーティングシステムが、同時に複数のスレッドを実行し、データアクセスを保護するために開発者に任せることで、複数のCPUとCPUコアを利用できることも意味します。
ファイバーの場合:現在の実行パスは、ファイバーが実行を生成したときにのみ中断されます(上記と同じ注意)。つまり、ファイバーは常に明確に定義された場所で開始および停止するため、データの整合性はそれほど問題になりません。また、ファイバーはユーザースペースで管理されることが多いため、高価なコンテキストスイッチやCPU状態の変更を行う必要がなく、ファイバー間の変更が非常に効率的になります。一方、2つのファイバーを同時に実行することはできないため、ファイバーを単独で使用するだけでは、複数のCPUまたは複数のCPUコアを利用することはできません。
スレッドはプリエンプティブスケジューリングを使用しますが、ファイバーは協調スケジューリングを使用します。
スレッドを使用すると、制御フローがいつでも中断され、別のスレッドが引き継ぐ可能性があります。複数のプロセッサを使用すると、複数のスレッドをすべて同時に実行できます(同時マルチスレッディング(SMT))。その結果、同時データアクセスに十分注意し、ミューテックス、セマフォ、条件変数などでデータを保護する必要があります。正しく理解するのは非常に難しいことがよくあります。
ファイバーの場合、制御は指示されたときにのみ切り替わります。通常は、のような名前の関数呼び出しを使用しますyield()
。これにより、データ構造やミューテックスの原子性について心配する必要がなくなるため、同時データアクセスが容易になります。譲歩しない限り、プリエンプションされて、別のファイバーが作業中のデータを読み取ったり変更したりする危険はありません。ただし、結果として、ファイバーが無限ループに入ると、降伏しないため、他のファイバーを実行できなくなります。
糸と繊維を混ぜることもできますが、これは両方が直面する問題を引き起こします。推奨されませんが、注意深く行うと正しい場合があります。
Win32では、ファイバーは一種のユーザー管理スレッドです。ファイバーには独自のスタックや独自の命令ポインターなどがありますが、ファイバーはOSによってスケジュールされていません。SwitchToFiberを明示的に呼び出す必要があります。対照的に、スレッドはオペレーティングシステムによってプリエンプティブにスケジュールされます。つまり、大まかに言えば、ファイバーは、真のOSスレッドではなく、アプリケーション/ランタイムレベルで管理されるスレッドです。
その結果、ファイバーが安価になり、アプリケーションがスケジューリングをより細かく制御できるようになります。これは、アプリが多数の同時タスクを作成する場合、および/またはそれらの実行時に厳密に最適化する場合に重要になる可能性があります。たとえば、データベースサーバーは、スレッドではなくファイバーを使用することを選択する場合があります。
(同じ用語に他の使用法がある場合があります。前述のように、これはWin32の定義です。)
まず、背景資料として プロセスとスレッドの違いに関するこの説明を読むことをお勧めします。
それを読んだら、それはかなり簡単です。スレッドは、カーネルまたはユーザー空間に実装するか、2 つを混在させることができます。ファイバーは基本的に、ユーザー空間に実装されたスレッドです。
- 通常、スレッドと呼ばれるものは、カーネルに実装された実行スレッドです。これは、カーネル スレッドとして知られています。カーネル スレッドのスケジューリングは、カーネルによって排他的に処理されますが、カーネル スレッドは、必要に応じてスリープすることで自発的に CPU を解放できます。カーネル スレッドには、ブロッキング I/O を使用できるという利点があり、カーネルにスケジューリングを心配させることができます。主な欠点は、カーネルへのトラップが必要なため、スレッドの切り替えが比較的遅いことです。
- ファイバーは、単一プロセスの下で 1 つ以上のカーネル スレッドによってユーザー空間でスケジューリングが処理されるユーザー空間スレッドです。これにより、ファイバーの切り替えが非常に高速になります。単一のカーネル スレッドのコンテキストで特定の共有データ セットにアクセスするすべてのファイバーをグループ化し、それらのスケジューリングを単一のカーネル スレッドで処理する場合、同期の問題を解消できます。スケジューリングを制御します。関連するファイバーを 1 つのカーネル スレッドの下にグループ化することは重要です。これは、ファイバーが実行されているカーネル スレッドがカーネルによって横取りされる可能性があるためです。この点は、他の多くの回答では明確にされていません。また、ファイバーでブロッキング I/O を使用する場合、カーネル スレッド全体が、そのカーネル スレッドの一部であるすべてのファイバーを含むブロックの一部になります。
最新のオペレーティング システムのセクション 11.4「Windows Vista のプロセスとスレッド」で、Tanenbaum は次のようにコメントしています。
ファイバーは協調的にスケジュールされますが、複数のスレッドがファイバーをスケジュールしている場合は、ファイバーが互いに干渉しないようにするために、多くの注意深い同期が必要です。スレッドとファイバー間の相互作用を単純化するには、スレッドを実行するプロセッサーと同数のスレッドのみを作成し、使用可能なプロセッサーの別個のセットでのみ、または 1 つのプロセッサーでのみ実行するようにスレッドをアフィニティー化すると便利なことがよくあります。各スレッドはファイバーの特定のサブセットを実行し、同期を簡素化するスレッドとファイバーの間に 1 対多の関係を確立します。とはいえ、繊維にはまだ多くの困難があります。ほとんどの Win32 ライブラリはファイバーをまったく認識しておらず、ファイバーをスレッドのように使用しようとするアプリケーションは、さまざまな障害に遭遇します。カーネルにはファイバーの知識がなく、ファイバーがカーネルに入ると、ファイバーが実行されているスレッドがブロックされる可能性があり、カーネルはプロセッサー上の任意のスレッドをスケジュールして、他のファイバーを実行できなくします。これらの理由から、ファイバーによって提供される機能を明示的に必要とする他のシステムからコードを移植する場合を除いて、ファイバーはめったに使用されません。
スレッドとファイバーに加えて、Windows 7 ではユーザー モード スケジューリングが導入されていることに注意してください。
ユーザー モード スケジューリング (UMS) は、アプリケーションが独自のスレッドをスケジュールするために使用できる軽量メカニズムです。アプリケーションは、システム スケジューラを使用せずにユーザー モードで UMS スレッドを切り替え、UMS スレッドがカーネルでブロックされた場合にプロセッサの制御を取り戻すことができます。UMS スレッドは、単一のスレッドのスレッド コンテキストを共有するのではなく、各 UMS スレッドが独自のスレッド コンテキストを持っているという点でファイバーとは異なります。ユーザー モードでスレッドを切り替える機能により、UMS はスレッド プールよりも効率的になり、システム コールをほとんど必要としない多数の短期間の作業項目を管理できます。
スレッド、ファイバー、UMS の詳細については、Dave Probert: Inside Windows 7 - User Mode Scheduler (UMS)をご覧ください。
スレッドは元々軽量プロセスとして作成されました。同様に、ファイバーは軽量のスレッドであり、制御を行うことにより、ファイバー自体に(単純に)依存して相互にスケジュールを設定します。
次のステップは、命令を実行するたびにシグナルを送信する必要があるストランドになると思います(私の5歳の息子とは異なります:-)。昔(そして今でも一部の組み込みプラットフォームでは)、すべてのスレッドはファイバーであり、プリエンプションはなく、正常に動作するようにスレッドを作成する必要がありました。
スレッドはOSによってスケジュールされます(プリエンプティブ)。スレッドはOSによっていつでも停止または再開できますが、ファイバーは多かれ少なかれそれ自体を管理し(協調的)、相互に譲歩します。つまり、プログラマーは、ファイバーが処理を実行するタイミングと、その処理が別のファイバーに切り替わるタイミングを制御します。
スレッドは通常、カーネルに依存してスレッドを中断し、スレッドまたは別のスレッドを実行できるようにします(これは、プリエンプティブマルチタスクとしてよく知られています)が、ファイバーは協調マルチタスクを使用します。他のファイバーは実行できます。
私がおそらくしたよりもそれをよりよく説明するいくつかの有用なリンクは次のとおりです。
Win32 ファイバーの定義は、実際には Sun Microsystems で確立された「グリーン スレッド」の定義です。ある種のスレッド、つまり、ユーザー コード/スレッド ライブラリの制御下でユーザー空間で実行されるスレッドでファイバーという用語を無駄にする必要はありません。
議論を明確にするために、次のコメントを見てください。
- ハイパースレッディングを使用すると、マルチコア CPU は複数のスレッドを受け入れ、各コアに 1 つずつ分散できます。
- スーパースカラーのパイプライン化された CPU は、実行用に 1 つのスレッドを受け入れ、命令レベルの並列処理 (ILP) を使用してスレッドをより高速に実行します。1 つのスレッドが、並列パイプラインで実行される並列ファイバーに分割されると想定できます。
- SMT CPU は複数のスレッドを受け入れ、それらを命令ファイバーに分割して、複数のパイプラインで並列実行できるため、パイプラインをより効率的に使用できます。
プロセスは糸でできており、糸は繊維でできているはずです。その論理を念頭に置いて、他の種類のスレッドにファイバーを使用することは間違っています.