go-langs goroutineプールは単なるグリーンスレッドですか?


47

ここでの解説は、グリーンスレッドの以下の批判を提供しています:

私は当初、コールバック地獄のないイベント駆動型プログラミングの手段としてN:Mモデルで販売されていました。古い手続き型コードのように見えるコードを書くことができますが、その下には、何かがブロックされるたびにユーザースペースのタスク切り替えを使用する魔法があります。いいね。問題は、複雑さをより複雑に解決することになるということです。swapcontext()およびファミリはかなり単純であり、複雑さは他の意図しない場所に由来します。

突然、ユーザー空間のスケジューラーを書くことを余儀なくされ、何年もかけて努力を重ねてきたLinuxのスケジュールよりも良い仕事をするスケジューラーを書くのは本当に難しいと思います。ここで、N個の緑色のスレッドからM個の物理的なスレッドをスケジュールして、同期を心配する必要があります。同期はパフォーマンスの問題を引き起こすため、新しいロックレスウサギの穴を掘って今すぐ始めます。正確で高度な並行スケジューラーを構築するのは簡単なことではありません。

別の批評はここにあります

複数のスレッドを偽装する単一のプロセスには、多くの問題があります。その1つは、偽のスレッドがすべてページフォールトで停止することです。

私の質問は- されて行く-LANGのゴルーチン(デフォルトプール用)ちょうどグリーンスレッド?もしそうなら-彼らは上記の批判に対処しますか?

回答:


67

私はただのGoユーザーであるため、次のことを一言で言ってください。

ウィキペディアでは、グリーンスレッドを「基礎となるオペレーティングシステムではなく、仮想マシン(VM)によってスケジュールされるスレッド」と定義しています。グリーンスレッドは、ネイティブOS機能に依存せずにマルチスレッド環境をエミュレートし、カーネルスペースではなくユーザースペースで管理されるため、ネイティブスレッドをサポートしていない環境で動作できます。

Go(または正確には2つの既存の実装)は、ネイティブコードのみを生成する言語です。VMは使用しません。さらに、現在のランタイム実装のスケジューラーは、OSレベルのスレッドに依存しています(GOMAXPROCS = 1の場合でも)。したがって、Goモデルのグリーンスレッドについて話すのは少し虐待的だと思います。

Goの人々は、特に他の同時実行メカニズム(コルーチンやスレッド、軽量プロセスなど)との混同を避けるためにゴルーチンの用語を作成しました。

もちろん、GoはM:Nスレッドモデルをサポートしていますが、JavaグリーンスレッドモデルよりもErlangプロセスモデルに非常に近いように見えます。

グリーンスレッド(初期のJVMに実装されている)に対するGoモデルの利点を次に示します。

  • 開発者にとって透過的な方法で、複数のコアまたはCPUを効果的に使用できます。Goを使用すると、開発者は並行性に注意する必要があります。Goランタイムは並列処理を行います。Javaグリーンスレッドの実装は、複数のコアやCPUにまたがってスケールしませんでした。

  • システムコールとCコールは、スケジューラに対してブロックされません(イベントループで多重化されたI / Oをサポートするコールだけでなく、すべてのシステムコール)。グリーンスレッドの実装は、ブロッキングシステムコールが行われたときにプロセス全体をブロックできました。

  • スタックのコピーまたはセグメント化。Goでは、ゴルーチンの最大スタックサイズを指定する必要はありません。スタックは必要に応じて徐々に大きくなります。その結果、ゴルーチンは多くのメモリ(4KB〜8KB)を必要としないため、大量のメモリを喜んで生成できます。したがって、ゴルーチンの使用は広範囲に及ぶ可能性があります。

今、批判に対処するために:

  • Goを使用すると、ユーザースペーススケジューラを作成する必要はありません。ランタイムに既に提供されています。複雑なソフトウェアですが、Goユーザーの問題ではなく、Go開発者の問題です。その使用法はGoユーザーには透過的です。Go開発者の中で、Dmitri Vyukovはロックフリー/ウェイトフリープログラミングの専門家であり、スケジューラの最終的なパフォーマンスの問題に対処することに特に興味があるようです。現在のスケジューラの実装は完全ではありませんが、改善されます。

  • 同期はパフォーマンスの問題と複雑さをもたらします。これはGoでも部分的に当てはまります。ただし、Goモデルは、チャネルの使用と並行ゴルーチンでのプログラムの完全な分解を促進して、同期の複雑さ(つまり、通信するメモリを共有するのではなく、通信によりデータを共有する)を促進しようとします。ところで、リファレンスGoの実装には、プロファイラー競合検出器など、パフォーマンスと同時実行の問題に対処するためのツールが多数用意されています。

  • ページフォールトと「複数のスレッドの偽造」に関して、Goは複数のシステムスレッドでゴルーチンをスケジュールできることに注意してください。1つのスレッドが何らかの理由(ページフォールト、システムコールのブロック)でブロックされた場合、他のスレッドが他のゴルーチンをスケジュールおよび実行し続けることを妨げません。これで、ページフォールトがOSスレッドをブロックし、すべてのゴルーチンがこのスレッドでスケジュールされることになります。ただし、実際には、Goヒープメモリはスワップアウトされることは想定されていません。これはJavaでも同じです。ガベージコレクションされた言語は、とにかく仮想メモリをうまく収容しません。プログラムがページフォールトを適切な方法で処理する必要がある場合(おそらく、オフヒープメモリを管理する必要があるため)。その場合、

IMOでは、ゴルーチンはグリーンスレッドではありません。Go言語と現在の実装は、主にこれらの批判に対処しています。


1
質問に対する優れた詳細な応答:)
タックスデュー

1
私はこの答えが大好きですが、OSスレッドがどのように/いつ作成されるかについての参照はありますか?
ラース

1
Go言語の最大の欠点の1つは、ブロッキングシステムコールごとにカーネルスレッドが作成されることです。
user1870400

8
ウィキペディアの「グリーンスレッド」の記事は、「ランタイムライブラリまたは仮想マシン(VM)によってスケジュールされたスレッド」を示すように変更されていることに注意してください。つまり、Goランタイムがスケジューリング/管理を行うため、その定義ではあなたの答えはもはや正しくないということです。OSスレッドとは対照的なユーザースペーススレッドとしてグリーンスレッドを定義する方が便利だと思います。そして、はい、ゴルーチンは確かに緑色の糸です。
mknecht

1
2番目の@mknecht。VMの問題ではなく、ランタイムの問題です。Goには必ずランタイムがあります。(スレッドモデルとガベージコレクションを管理します)。
ティムハーパー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.