web-dev-qa-db-ja.com

C#非同期-どのように機能しますか?

マイクロソフトは、非同期メソッド実行のためにasyncおよびawaitキーワードをC#/ VBに導入する Visual Studio Async CTP 本日(2010年10月28日)を発表しました。

最初に、コンパイラがキーワードをスレッドの作成に変換すると思いましたが、 ホワイトペーパー およびAnders Hejlsbergの PDCプレゼンテーション (31:00)によると非同期操作が発生します完全にメインスレッド上にあります。

同じスレッドで操作を並行して実行するにはどうすればよいですか?それはどのように技術的に可能であり、ILで実際に翻訳された機能は何ですか?

47
Dirk Vollmar

これは、C#2.0のyield returnキーワードと同様に機能します。

非同期方式は、実際には通常の順次方式ではありません。いくつかの状態を持つステートマシン(オブジェクト)にコンパイルされます(ローカル変数はオブジェクトのフィールドに変換されます)。 awaitの2つの使用の間のコードの各ブロックは、ステートマシンの1つの「ステップ」です。

つまり、メソッドが開始すると、最初のステップが実行され、ステートマシンが戻って、実行する作業をスケジュールします。作業が完了すると、ステートマシンの次のステップが実行されます。たとえば、次のコード:

async Task Demo() { 
  var v1 = foo();
  var v2 = await bar();
  more(v1, v2);
}

次のようなものに翻訳されます:

class _Demo {
  int _v1, _v2;
  int _state = 0; 
  Task<int> _await1;
  public void Step() {
    switch(this._state) {
    case 0: 
      this._v1 = foo();
      this._await1 = bar();
      // When the async operation completes, it will call this method
      this._state = 1;
      op.SetContinuation(Step);
    case 1:
      this._v2 = this._await1.Result; // Get the result of the operation
      more(this._v1, this._v2);
  }
}

重要な部分は、SetContinuationメソッドを使用して、操作が完了したときにStepメソッドを再度呼び出す必要があることを指定することです(メソッドは、の2番目のビットを実行する必要があることを認識しています。 _stateフィールドを使用した元のコード)。 SetContinuationbtn.Click += Stepのようなものであり、完全に単一のスレッドで実行されることは容易に想像できます。

C#の非同期プログラミングモデルはF#非同期ワークフローに非常に近く(実際、技術的な詳細を除けば本質的に同じです)、asyncを使用してリアクティブなシングルスレッドGUIアプリケーションを作成することは非常に興味深いことです。エリア-少なくとも私はそう思います-たとえばを参照してください この記事 (多分私は今C#バージョンを書くべきです:-))。

変換はイテレーター(およびyield return)に似ており、実際、イテレーターを使用して以前のC#で非同期プログラミングを実装することができました。私は それについての記事 少し前に書いた-そしてそれはまだあなたに翻訳がどのように機能するかについての洞察を与えることができると思う。

81
Tomas Petricek

同じスレッドで操作を並行して実行するにはどうすればよいですか?

できません。 非同期は「並列処理」または「並行処理」ではありません。非同期は並列処理で実装される場合とそうでない場合があります。これは、作業を小さなチャンクに分割し、作業の各チャンクをキューに入れ、スレッドが他に何もしていないときはいつでも、作業の各チャンクを実行することによって実装される場合があります。

私のブログには、これらすべてがどのように機能するかについての一連の記事があります。この質問に直接関係するものは、おそらく来週の木曜日に上がるでしょう。見る

http://blogs.msdn.com/b/ericlippert/archive/tags/async/

詳細については。

46
Eric Lippert

私が理解しているように、asyncおよびawaitキーワードが行うことは、asyncメソッドがawaitキーワードを使用するたびに、コンパイラーが剰余を変換することです。非同期操作が完了したときにスケジュールされる継続へのメソッドの変換。これにより、asyncメソッドはすぐに呼び出し元に戻り、非同期部分が完了したときに作業を再開できます。

入手可能な論文によると、それには多くの詳細がありますが、私が間違っていない限り、それがその要点です。

私が見ているように、非同期メソッドの目的は、多くのコードを並行して実行することではなく、必要に応じて呼び出すことができるいくつかの小さなチャンクに非同期メソッドを分割することです。重要な点は、コンパイラーがタスク/継続を使用してコールバックのすべての複雑な配線を処理することです。これにより、複雑さが軽減されるだけでなく、非同期メソッドを従来の同期コードとほぼ同じように記述できます。

8
Brian Rasmussen