web-dev-qa-db-ja.com

コルーチン(ゴルーチンとコトリンコルーチン)のどれが速いですか?

Kotlin corutinesは、有限状態マシンと一部のタスクランナー(デフォルトのForkJoinPoolなど)の砂糖です。 https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#implementation-details

つまり、Java/kotlinランタイムにはまだランタイムコルーチンはありません(ただし、これは http://cr.openjdk.Java.net/~rpressler/loom/Loom-Proposal.html で変更できます) )。 Kotlinコルーチンは、タスクを1つずつ実行するだけの連続です。各タスクは、スレッドプールの任意のスレッドで実行できます。

Goランタイムは「コルーチン」をサポートしています。しかし、ゴルーチンは本当のコルーチンではありません。ゴルーチンは、プログラムで降伏点を設定することを許可しません。また、Goでは、カスタムスレッドプールを設定できません。デフォルトプールのスレッドのサイズのみを設定できます。

Kotlinコルーチンとgoroutinesの最初の違いは、Goランタイムが現在どのコルーチンが実行されているかを管理することです。ゴルーチンがいくつかのIO操作(または同期プリミティブ))でブロックされると、Goが次に実行するジョブを選択します。

このため、Goは現在実行中のジョブを安価に変更できます。 Goはいくつかのレジストリを変更するだけです https://groups.google.com/forum/#!msg/golang-nuts/j51G7ieoKh4/wxNaKkFEfvcJ 。しかし、JVMはレジスタを使用する代わりにスレッドのスタックを使用できると言う人もいます。したがって、レジスタの保存とロードはまったくありません。

コトリンコルーチンとゴルーチンの2番目の違いは、コルーチンのタイプです。 Kotlinコルーチンはスタックレスコルーチンです。ゴルーチンはスタックフルコルーチンです。 Kotlinコルーチンのすべての状態は、ヒープに格納されているKotlinコンテキストに格納されます。ゴルーチンの状態は、レジスタとスレッドスタックに格納されます。

知りたいのは、IOバインドされたタスク?CPUバインドされたタスク?メモリ消費はどうですか?

23
Max

KotlinのコルーチンはGoのゴルーチンとは異なる方法で実装されているため、どちらが「速い」かは、解決しようとしている問題と作成しているコードの種類によって異なります。

一般に、手元にある問題に対してどれがうまく機能するかを事前に伝えることは非常に困難です。特定のワークロードのベンチマークを実行して、それを把握する必要があります。ただし、いくつかのガイダンスを提供する重要な違いの概要を以下に示します。

  • Kotlinコルーチンは、Goゴルーチンよりも単純なインスタンスごとに必要なメモリが少なくなります。 Kotlinの単純なコルーチンはヒープメモリの数十バイトしか占有しませんが、Goゴルーチンは4KiBのスタックスペースで始まります。つまり、文字通り何百万ものコルーチンを使用することを計画している場合、KotlinのコルーチンはEdge対Goを提供するかもしれません。また、ジェネレーターや遅延シーケンスのような非常に短命で小さなタスクに適したKotlinコルーチンを作成します。

  • Kotlinコルーチンは任意のスタックの深さに移動できますが、一時停止関数を呼び出すたびに、スタックのオブジェクトがヒープに割り当てられます。 Kotlinコルーチンの呼び出しスタックは、現在、ヒープオブジェクトのリンクリストとして実装されています。対照的に、Goのゴルーチンは線形スタックスペースを使用します。これにより、Goでディープスタックのサスペンションがより効率的になります。したがって、記述しているコードがスタックの非常に深いところにある場合、ゴルーチンがより効率的であることがわかります。

  • 効率的な非同期IOは非常に多次元の設計上の問題です。ある種のアプリケーションにとって効率的なアプローチでは、別のアプリケーションに最高のパフォーマンスが得られない可能性があります。すべてIO Kotlinコルーチンの操作は、KotlinまたはJavaで記述されたライブラリによって実装されます。Kotlinコードで利用できるIOライブラリは多種多様です。Go非同期ではIO is一般的なGoコードでは使用できないプリミティブを使用してGoランタイムによって実装されます。IO操作を実装するためのGoアプローチがアプリケーションに適している場合、Goランタイムとの緊密な統合により、一方、Kotlinではライブラリを見つけるか、非同期IOをアプリケーションに最適な方法で実装するライブラリを自分で作成できます。

  • Goランタイムは、物理OSスレッドでのゴルーチンの実行を完全に制御します。このアプローチの利点は、すべてを考慮する必要がないことです。 Kotlinコルーチンを使用すると、コルーチンの実行環境をきめ細かく制御できます。これはエラーが発生しやすいです(たとえば、作成するスレッドプールが多すぎて、コンテキスト間の切り替えにCPU時間を浪費する可能性があります)。ただし、アプリケーションのスレッド割り当てとコンテキストスイッチを微調整することができます。たとえば、Kotlinでは、アプリケーション全体またはそのコードのサブセットを単一のOSスレッド(またはスレッドプール)で簡単に実行して、適切なコードを記述するだけでOSスレッド間のコンテキストの切り替えを完全に回避できます。

60
Roman Elizarov