最近、オペレーティング システムのクラスでスレッドについて頻繁に話し合っていますが、1 つの疑問が頭に浮かびました。
Go (および Java) はカーネル スレッドの代わりにユーザー空間スレッドを使用するため、OS はスレッド自体ではなくプロセスにのみ CPU 時間を割り当てるため、複数のコアを効果的に利用できないということではないでしょうか?
最近、オペレーティング システムのクラスでスレッドについて頻繁に話し合っていますが、1 つの疑問が頭に浮かびました。
Go (および Java) はカーネル スレッドの代わりにユーザー空間スレッドを使用するため、OS はスレッド自体ではなくプロセスにのみ CPU 時間を割り当てるため、複数のコアを効果的に利用できないということではないでしょうか?
Go がユーザー空間スレッドを使用していると思われる理由は何ですか?
そうではありません。OS スレッドを使用し、複数のコアを利用できます。
デフォルトでは、Go がプログラムを実行するために 1 つのスレッドしか使用しないことに戸惑うかもしれません。2 つのゴルーチンを開始すると、それらは 1 つのスレッドで実行されます。しかし、1 つの goroutine が I/O Go をブロックすると、2 番目のスレッドが作成され、新しいスレッドで他の goroutine が引き続き実行されます。
マルチコアの能力を完全に解き放ちたい場合は、GOMAXPROCS()
関数を使用してください。
runtime.GOMAXPROCS(4); //somewhere in main
これで、プログラムは (1 つではなく) 4 つの OS スレッドを使用し、たとえば 4 コア システムを完全に使用できるようになります。
Java の最新バージョンは OS スレッドを使用しますが、必ずしも Java スレッドとの 1 対 1 のマッピングがあるわけではありません。Java は明らかに、多くのハードウェア スレッド間で非常にうまく機能します。
「ユーザー空間スレッド」とは、(たとえば)Goのゴルーチンを意味すると思います。
並行性のためにゴルーチンを使用することは、作業単位を OS スレッドに割り当てるための専用アルゴリズムを (手動および科学計算によって) 設計するよりも効率が悪いことは事実です。
ただし、すべての Go プログラムは環境内にあり、特定の問題を解決するように設計されています。環境がGoプログラムに対して行うリクエストごとに、新しいゴルーチンを開始できます。環境が Go プログラムに対して同時要求を行っている場合、Go プログラムが 1 つの OS スレッドしか使用していない場合でも、ゴルーチンを使用する Go プログラムはシリアル プログラムよりも高速に実行できる可能性があります。goroutine がより高速にリクエストを処理できる理由 (1 つの OS スレッドのみを使用している場合でも) は、A に関連付けられている環境の一部が一時的に使用できない場合、Go プログラムが goroutine A から goroutine B に自動的に切り替えるためです。応答。
しかし、確かに、ゴルーチンを使用してそれらを複数の OS スレッドに自動的に割り当てることは、作業単位を OS スレッドに割り当てるための専用アルゴリズムを (手動および科学計算によって) 設計するよりも効率的ではありません。