10

Python では、yield キーワードはプッシュ コンテキストとプル コンテキストの両方で使用できます。C# でプル コンテキストを実行する方法は知っていますが、プッシュを実現するにはどうすればよいでしょうか。Python から C# で複製しようとしているコードを投稿します。

def coroutine(func):
  def start(*args,**kwargs):
    cr = func(*args,**kwargs)
    cr.next()
    return cr
  return start

@coroutine
def grep(pattern):
  print "Looking for %s" % pattern
  try:
    while True:
      line = (yield)
      if pattern in line:
        print line,
  except GeneratorExit:
    print "Going away. Goodbye"
4

7 に答える 7

14

必要なものが「監視可能なコレクション」、つまり、消費者に結果をプルさせるのではなく、結果をプッシュするコレクションである場合は、おそらく Reactive Framework 拡張機能を検討することをお勧めします。これに関する記事は次のとおりです。

http://www.infoq.com/news/2009/07/Reactive-Framework-LINQ-Events

お気づきのように、コルーチンが利用可能であれば、「プッシュ」スタイルと「プル」スタイルの両方のイテレーターを簡単に作成できます。(または、Thomas が指摘しているように、継続を使用してそれらを構築することもできます。) C# の現在のバージョンでは、真のコルーチン (または継続) がありません。しかし、非同期プログラミングに関してユーザーが感じる苦痛については非常に懸念しています。

第一級の言語機能としてファイバーベースのコルーチンを実装することは、非同期プログラミングをより簡単にするために使用できる可能性のある手法の 1 つですが、それは私たちが現在研究している多くのアイデアの 1 つにすぎません。リアクティブ フレームワークを含め、コルーチンが他の何よりも優れた機能を発揮する、本当に堅実で素晴らしいシナリオがある場合は、ぜひ詳しくお聞かせください。人々が非同期プログラミングで直面している実際の問題について、より現実的なデータがあればあるほど、優れた解決策を思いつく可能性が高くなります。ありがとう!

更新: コルーチンのような非同期制御フローを C# および VB の次のバージョンに追加することを最近発表しました。ここからダウンロードできる Community Technology Preview エディションを使用して、実際に試すことができます。

于 2010-03-22T18:12:39.440 に答える
7

C# には一般的なコルーチンがありません。一般的なコルーチンは、コルーチンが独自のスタックを持つ場所です。つまり、コルーチンは他のメソッドを呼び出すことができ、それらのメソッドは値を「生成」できます。一般的なコルーチンの実装には、スタックを使用していくつかのスマートなものを作成する必要があり、場合によってはスタック フレーム (ローカル変数を含む隠し構造) をヒープに割り当てることも含まれます。これは可能で、一部の言語 (Scheme など) では実行できますが、正しく実行するのは少し難しいです。また、多くのプログラマーはこの機能を理解するのが難しいと感じています。

一般的なコルーチンは、スレッドでエミュレートできます。各スレッドには独自のスタックがあります。コルーチンのセットアップでは、両方のスレッド (最初の呼び出し元とコルーチンのスレッド) が交互に制御し、実際に同時に実行されることはありません。「yield」メカニズムは 2 つのスレッド間の交換であり、そのためコストがかかります (同期、OS カーネルお​​よびスケジューラーを介したラウンドトリップ...)。また、メモリ リークの余地が大きくなります (コルーチンを明示的に "停止" する必要があります。そうしないと、待機中のスレッドが永久に残ります)。したがって、これが行われることはめったにありません。

C# は、 iteratorsと呼ばれる粗末なコルーチン機能を提供します。C# コンパイラは、反復子コードを特定の状態クラスに自動的に変換し、ローカル変数がクラス フィールドになります。その場合、Yielding は VM レベルでは単純なreturn. このようなことは、イテレータ コードが呼び出すメソッドからではなく、イテレータ コード自体から「yield」が実行される限り実行可能です。C# の反復子は既に多くのユース ケースをカバーしており、C# の設計者は継続への道をさらに進めようとはしませんでした。一部の皮肉屋は、フル機能の継続を実装すると、C# がその宿敵である Java ほど効率的ではなくなるだろうと述べています (効率的な継続は実行可能ですが、これには GC と JIT コンパイラでかなりの作業が必要です)。

于 2010-03-22T15:41:04.390 に答える
3

ありがとう@NickLarsen、MSが導入した新しいもの、IObservableインターフェースを思い出すのを手伝ってくれました。

リンクhttp://msdn.microsoft.com/en-us/library/dd783449(VS.100).aspx

于 2010-03-22T15:24:26.947 に答える
3

多分これが役立つでしょう。

http://blogs.msdn.com/ericlippert/archive/2009/07/23/iterator-blocks-part-five-push-vs-pull.aspx

于 2010-03-22T15:12:31.173 に答える
1

実際、.NET はスレッド アフィニティについて「誤った仮定」を行っていません。実際、.NET レベルのスレッドの概念を OS レベルのスレッドから完全に分離しています。

あなたがしなければならないことは、論理的な .NET スレッド状態をファイバーに関連付けることです (そのためには、CLR ホスティング API が必要ですが、自分でホストを作成する必要はありません。自分のアプリケーションから必要なものを直接使用できます)。ロック トラッキング、例外処理が正常に動作するようになりました。

例はここにあります: http://msdn.microsoft.com/en-us/magazine/cc164086.aspx

ところで、Mono 2.6 には低レベルのコルーチン サポートが含まれており、すべての高レベルのプリミティブを簡単に実装するために使用できます。

于 2010-07-07T22:08:14.217 に答える
0

.Net用のファイバーベースのAPIが欲しいです。

しばらく前にp/invokeを介してC#でネイティブファイバーAPIを使用しようとしましたが、ランタイムの例外処理が(誤って)スレッドベースの仮定を行うため、例外が発生すると(ひどく)問題が発生しました。

ファイバーベースのコルーチンAPIの「キラーアプリ」の1つは、ゲームプログラミングです。特定の種類のAIには、自由にタイムスライスできる「軽量」スレッドが必要です。たとえば、ゲームの動作ツリーには、フレームごとに決定コードを「パルス」する機能が必要です。これにより、決定スライスがアップしたときにAIコードが協調して呼び出し元に戻ることができます。これはハードスレッドで実装することは可能ですが、はるかに複雑です。

したがって、真のファイバーのユースケースは主流ではありませんが、それらは間違いなく存在し、ファイバーサブシステムの既存のバグが解決されれば、私たち.Netコーダーの小さなニッチは大いに応援します。

于 2010-07-04T05:58:49.437 に答える
0

さて、単一のスレッドだけでコルーチンを管理するための完全なライブラリを開発してみました。難しい部分は、コルーチン内でコルーチンを呼び出すことと、パラメーターを返すことでしたが、最終的にここでかなり良い結果に達しました。唯一の警告は、ブロッキング I/O 操作はタスクを介して行う必要があり、すべての「リターン」を「イールド リターン」に置き換える必要があることです。このライブラリに基づくアプリケーション サーバーを使用すると、IIS に基づく標準の async/await で行われた要求をほぼ 2 倍にすることができました。(自宅で試すには、github で Node.Cs と Node.Cs.Musicstore を探します)

于 2014-04-22T18:18:01.413 に答える