Boost :: Coroutine2とCoroutineTS(C ++ 20)は、C ++で人気のあるコルーチンの実装です。どちらも一時停止と再開を行いますが、2つの実装はまったく異なるアプローチに従います。
CoroutineTS(C ++ 20)
generator<int> Generate()
{
co_yield;
});
boost :: coroutine2
pull_type source([](push_type& sink)
{
sink();
});
そのうちの1つだけを選択する必要がある特定のユースケースはありますか?
主な技術的な違いは、ネストされた呼び出し内から譲歩できるようにするかどうかです。これは、スタックレスコルーチンを使用して行うことはできません。
考慮すべきもう1つの点は、スタックフルコルーチンには独自のスタックとコンテキスト(シグナルマスク、スタックポインター、CPUレジスターなど)があるため、スタックレスコルーチンよりもメモリフットプリントが大きいことです。これは、リソースに制約のあるシステムや大量のコルーチンが同時に存在する場合に特に問題になる可能性があります。
現実の世界でパフォーマンスをどのように比較するかはわかりませんが、一般に、スタックレスコルーチンはオーバーヘッドが少ないため、より効率的です(スタックレスタスクスイッチは、スタックを交換したり、レジスタを格納/ロードしたり、信号を復元したりする必要がありません)。マスクなど)。
最小のスタックレスコルーチンの実装の例については、サイモン・タタムのコルーチンを使用ダフのデバイス。それらがあなたが得ることができるのと同じくらい効率的であることはかなり直感的です。
また、この質問には、スタックフルコルーチンとスタックレスコルーチンの違いについて詳しく説明する優れた回答があります。
スタックレスコルーチンでネストされた呼び出しから譲る方法は? 不可能だと言ったとしても、それは100%真実ではありませんでした:これを達成するために(少なくとも2つの)トリックを使用できますが、それぞれにいくつかの欠点があります:まず、呼び出しコルーチンを生成できるはずのすべての呼び出しを変換する必要がありますコルーチンにも。現在、2つの方法があります。
トランポリンのアプローチ:それが戻るまであなたは単に、ループ内の親コルーチンから子コルーチンを呼び出します。子コルーチンに通知するたびに、それが終了しない場合は、呼び出しコルーチンも生成します。このアプローチでは、子コルーチンを直接呼び出すことは禁止されていることに注意してください。常に最も外側のコルーチンを呼び出す必要があり、その後、コールスタック全体に再入力する必要があります。これには、ネストの深さnに対してO(n)の呼び出しと戻りの複雑さがあります。イベントを待っている場合、イベントは単に最も外側のコルーチンに通知する必要があります。
親リンクのアプローチ:あなたが親コルーチンを得、子コルーチンに親コルーチンアドレスを渡し、それが終了すると、子コルーチンを手動で親コルーチンを再開します。このアプローチでは、最も内側のコルーチン以外のコルーチンを直接呼び出すことは禁止されていることに注意してください。このアプローチは、呼び出しと戻りの複雑さがO(1)であるため、一般的に推奨されます。欠点は、最も内側のコルーチンをどこかに手動で登録する必要があるため、外側のコルーチンを再開したい次のイベントが、どの内側のコルーチンを直接ターゲットにするかを認識できることです。
注:呼び出しと戻りの複雑さとは、コルーチンに再開を通知するときに実行する手順の数と、呼び出し通知に再び戻るように通知した後に実行する手順を意味します。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加