web-dev-qa-db-ja.com

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

コメンテーターはこちら は、グリーンスレッドに関する次の批判を提供します。

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

突然、ユーザースペーススケジューラーを作成することを余儀なくされ、何年にもわたる労力を費やしたLinuxのスケジュールよりも優れた仕事をするスケジューラーを作成するのが本当に難しいと思います。次に、N個のグリーンスレッドからM個の物理スレッドにスケジュールを設定して、同期について心配する必要があります。同期によってパフォーマンスの問題が発生するため、今すぐ始めましょう。新しいロックレスのうさぎの穴に突き当たります。正確で並行性の高いスケジューラを構築することは簡単な作業ではありません。

別の 批評はこちら

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

私の質問は-are go-lang's goroutines (for a default pool)just green threads?もしそうなら-彼らは上記の批判に対処していますか?

50
hawkeye

私はカジュアルなGoユーザーなので、次のことを1粒の塩で味わってください。

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

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

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

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

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

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

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

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

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

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

  • 同期はパフォーマンスの問題と複雑さをもたらします。これはGoでも部分的に当てはまります。ただし、Goモデルは、同時goroutineでのチャネルの使用とプログラムのクリーンな分解を促進して、同期の複雑さを制限しようとしていることに注意してください(つまり、通信するためにメモリを共有する代わりに、通信によってデータを共有します)。ちなみに、リファレンスGoの実装には、パフォーマンスと同時実行性の問題に対処するための profilerrace Detector などのツールがいくつか用意されています。

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

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

69
Didier Spezia