どんなゴルーチン?
ゴルーチンは、同じアドレス空間にある他のゴルーチンと競争的に実行する機能です。
goroutineの実行は非常に簡単です。
go normalFunc(args...)
normalFunc(args...)
関数は、それを呼び出したコードと非同期に開始します。
ゴルーチンは非常に軽量であることに注意してください。 ほぼすべての費用はスタックの作成であり、必要に応じて拡大できますが、非常に小さいです。
グラム単位でいくらですか?
ナビゲートしやすくするために、 経験的に得られた数値を考慮してください。
平均して、 ゴルーチンごとに約4.5kbを期待できます。 つまり、たとえば、4GbのRAMがある場合、約80万個の作業用ゴルーチンを含めることができます。 たぶん、これはErlangファンを感動させるのに十分ではありませんが、私にはその数字は非常にまともなようです:)
それでも、可能な限りgoroutineに機能を無意識に割り当てるべきではありません。 これは、次の場合に利点をもたらします。
- 非同期が必要な場合。 たとえば、ネットワーク、ディスク、データベース、ミューテックスで保護されたリソースなどを使用する場合
- 関数の実行時間が十分に長く、他のカーネルをロードすることで利益が得られる場合。
「十分な」-いくらですか? これは難しい質問です。 ほとんどの場合、特定の状況に応じて決定する必要があります。 私のハードウェア(atom d525 64bit)での経験から、それは〜50μsであるとしか言えません。 一般的に、フレアをテストして開発します;)
システムスレッド
ソースコード( src / pkg / runtime / proc.c )では次の用語が受け入れられます 。
G(ゴルーチン)-ゴロティナ
M(マシン)-マシン
各マシンは別々のスレッドで動作し、一度に1つのGorutinのみを実行できます。 プログラムが実行されるオペレーティングシステムのスケジューラは、マシンを切り替えます。 実行中のマシンの数は、
GOMAXPROCS
環境
GOMAXPROCS
または
runtime.GOMAXPROCS(n int)
関数によって制限されます。 デフォルトでは1です。通常、コアの数と等しくするのが理にかなっています。
Go Scheduler
スケジューラの目標は、すぐに実行できるゴルーチン(G)を空きマシン(M)に配布することです。
スケジューラの図と説明は、 Google Goの Sindre Myren RT Capabillitesの研究から引用したものです。
すぐに使用できるゴルーチンは、優先順位の順に実行されます。つまり、FIFO(先入れ先出し)です。 ゴルーチンの実行は、 システムコールまたは同期オブジェクト (チャネル、ミューテックスなどの操作)の使用が原因で実行できなくなった場合にのみ中断されます 。 goroutineの作業にはタイムスライスがありません。その後、再びキューに戻されます。 スケジューラーがこれを行えるようにするには、
runtime. Gosched ()
自分で呼び出す必要があります
runtime. Gosched ()
runtime. Gosched ()
。
関数の実行準備が整うとすぐに、再びキューに入ります。
結論
私はすぐに、現状が私を驚かせたと言います。 なんらかの理由で、無意識のうちに、「並列性」の向上を期待していました。おそらく、ゴルーチンを軽量のシステムフローとして認識しているからでしょう。 ご覧のとおり、これは完全に真実ではありません。
実際には、これは主に、
runtime. Gosched ()
を使用する価値があることを意味し
runtime. Gosched ()
runtime. Gosched ()
。これにより、いくつかの長命のゴルーチンが、他のすべてのゴルーチンの作業を大幅に停止しないようにします。 一方、そのような状況は実際には非常にまれです。
また、現時点では、ドキュメントと公式FAQに記載されているように、スケジューラは決して完璧ではありません。 深刻な改善が将来計画されています。 個人的には、ゴルーチンを優先する可能性を主に期待しています。