web-dev-qa-db-ja.com

GoプログラムですべてのCPUコアをビジー状態に保つにはどうすればよいですか?

ゴルーチンは、Goランタイムによって1つ以上のオペレーティングシステムスレッドに自動的にタイムスライスされる軽量プロセスです。 (これはGoの本当にクールな機能です!)

Webサーバーのような並行アプリケーションがあるとします。私の仮説のプログラムでは、多くの非並行(アムダールの法則)の比率なしに、同時に起こることがたくさんあります。

現在使用中のオペレーティングシステムスレッドのデフォルト数は1のようです。これは、1つのCPUコアのみが使用されることを意味しますか?

プログラムを開始する場合

runtime.GOMAXPROCS(runtime.NumCPU())

all PCのコアを合理的に効率的に使用できますか?

さらに多くのOSスレッドを使用することによる「並列スラックネス」の利点はありますか?いくつかのヒューリスティック経由

runtime.GOMAXPROCS(runtime.NumCPU() * 2)

35
Rick-777

Go FAQから:

なぜマルチゴルーチンプログラムが複数のCPUを使用しないのですか?

GOMAXPROCSシェル環境変数を設定するか、ランタイムパッケージの同様の名前の関数を使用して、ランタイムサポートが複数のOSスレッドを利用できるようにする必要があります。

並列計算を実行するプログラムは、GOMAXPROCSの増加の恩恵を受けるはずです。ただし、並行性は並列処理ではないことに注意してください。

(2015年8月28日更新:Go 1.5は、GOMAXPROCSのデフォルト値をマシンのCPU数と同じにするように設定されているため、これはもう問題になりません)

そして

なぜGOMAXPROCS> 1を使用するとプログラムが遅くなるのですか?

それはあなたのプログラムの性質に依存します。本質的に連続した問題は、ゴルーチンを追加することでスピードアップできません。並行性は、問題が本質的に並列である場合にのみ並列性になります。

実際には、複数のOSスレッドを使用すると、計算を行うよりもチャネルでの通信に多くの時間を費やすプログラムのパフォーマンスが低下します。これは、スレッド間でデータを送信するにはコンテキストの切り替えが伴うため、多大なコストがかかるためです。たとえば、Go仕様のプライムシーブの例には、多くのゴルーチンが起動されますが、重要な並列性はありません。 GOMAXPROCSを増やすと、スピードアップするよりもスローダウンする可能性が高くなります。

Goのgoroutineスケジューラは、必要なほど良くありません。将来的には、そのような場合を認識し、OSスレッドの使用を最適化する必要があります。今のところ、GOMAXPROCSはアプリケーションごとに設定する必要があります。

要するに、Goで「すべてのコアを効率的に使用」することは非常に困難です。数十億のゴルーチンを生成してGOMAXPROCSを増やすだけでは、スレッドコンテキストが常に切り替わるため、速度が上がるのと同じくらいパフォーマンスが低下する可能性があります。並列化可能な大規模なプログラムがある場合、GOMAXPROCSを並列コンポーネントの数に増やすとうまくいきます。主に非並列プログラムに埋め込まれた並列の問題がある場合、速度が上がるか、runtime.LockOSThread()のような関数を創造的に使用して、ランタイムがすべてを正しく配布するようにしなければならない場合があります現在、すべてのアクティブなスレッド間で無計画かつ均等に非ブロッキングゴルーチンが実行されます)。

また、GOMAXPROCSは使用するCPUコアの数です。これがNumCPUより大きい場合は、単にNumCPUに固定されると確信しています。 GOMAXPROCSは、スレッドの数と厳密には等しくありません。ランタイムが新しいスレッドを生成することを決定する正確なタイミングは100%わかりませんが、1つのインスタンスは、runtime.LockOSThread()を使用するブロックゴルーチンの数がGOMAXPROCs以上の場合です-コアより多くのスレッドを生成しますそのため、プログラムの残りの部分を正常に実行できます。

基本的に、GOMAXPROCSを増やしてgo seをCPUのすべてのコアにすることは非常に簡単です。 Goの開発のこの時点で、実際にそれを実現することはまったく別のことですスマートかつ効率的に使用 CPUのすべてのコアであり、正しく動作するには多くのプログラム設計と手間が必要です。

56
LinearZoetrope

この質問には答えられず、あまりにも広範です。

問題、アルゴリズム、ワークロードを取り、この組み合わせに最適なものを測定します。

「昼食に2倍の塩を加えると味が良くなるという経験則はありますか?」などの質問に答えることはできません。これは昼食に依存するため(トマトはイチゴよりも塩の恩恵が大きい)あなたの味と塩の量はすでにあります。それを試してみてください。

さらに:runtime.GOMAXPROCS(runtime.NumCPU())はカルトステータスを達成していますが、GOMAXPROCS環境変数をoutsideから設定することでスレッド数を制御する方がはるかに優れたオプションです。

4
Volker

runtime.GOMAXPROCS()は、プログラムが同時に使用できる(仮想)CPUコアの数を設定します。ご使用のシステムには非常に多くのCPUコアしか搭載されていないため、Goで実際に使用するよりも多くのCPUコアを使用することはできません。

複数のスレッドで実行するには、プログラムにいくつかのゴルーチン、通常はgo someFunc()を使用した関数呼び出しが必要です。プログラムが追加のゴルーチンを開始しない場合、使用できるCPU /コアの数に関係なく、自然に1つのスレッドでのみ実行されます。

this と、ゴルーチンの作成方法に関する以下の演習を確認してください。

0
sjakobi