web-dev-qa-db-ja.com

新しいC#待機機能とは何ですか?

誰でもawait関数の機能を説明できますか?

82
Chris Nicol

彼らはただ PDCでこれについて話した 昨日!

Awaitは、.NETのタスク(並列プログラミング)と組み合わせて使用​​されます。これは、次のバージョンの.NETで導入されるキーワードです。多かれ少なかれ、メソッドの実行を「一時停止」して、タスクの実行が完了するのを待ちます。以下に簡単な例を示します。

//create and run a new task  
Task<DataTable> dataTask = new Task<DataTable>(SomeCrazyDatabaseOperation);

//run some other code immediately after this task is started and running  
ShowLoaderControl();  
StartStoryboard();

//this will actually "pause" the code execution until the task completes.  It doesn't lock the thread, but rather waits for the result, similar to an async callback  
// please so also note, that the task needs to be started before it can be awaited. Otherwise it will never return
dataTask.Start();
DataTable table = await dataTask;

//Now we can perform operations on the Task result, as if we're executing code after the async operation completed  
listBoxControl.DataContext = table;  
StopStoryboard();  
HideLoaderControl();
61
RTigger

基本的に、asyncおよびawaitキーワードを使用すると、非同期メソッド呼び出しをマークするawaitのすべての使用でメソッドの実行を停止するように指定できます。非同期操作が完了しました。これにより、アプリケーションのメインスレッドでメソッドを呼び出して、複雑な作業を非同期で処理できます。スレッドと結合を明示的に定義したり、アプリケーションのメインスレッドをブロックしたりする必要はありません。

IEnumerableを生成するメソッドのyield returnステートメントに多少似ていると考えてください。ランタイムがyieldにヒットすると、基本的にメソッドの現在の状態を保存し、生成された値または参照を返します。次回IEnumerator.MoveNext()が戻りオブジェクト(ランタイムによって内部的に生成される)で呼び出されると、メソッドの古い状態がスタックに復元され、yield returnの後の次の行で実行が続行されますメソッドを終了することはありませんでした。このキーワードを使用しない場合、IEnumerator型は、実際に非常に複雑になる可能性があるメソッドを使用して、状態を保存し、反復要求を処理するためにカスタム定義する必要があります。

同様に、asyncとしてマークされたメソッドには、少なくとも1つのawaitが必要です。 awaitで、ランタイムは現在のスレッドの状態と呼び出しスタックを保存し、非同期呼び出しを行い、ランタイムのメッセージループに戻って次のメッセージを処理し、アプリの応答性を維持します。非同期操作が完了すると、次のスケジューリングの機会に、非同期操作を開始する呼び出しスタックがプッシュバックされ、あたかも呼び出しが同期であるかのように継続されます。

したがって、これらの2つの新しいキーワードは、yield returnがカスタム列挙可能要素の生成を単純化したように、基本的に非同期プロセスのコーディングを単純化します。いくつかのキーワードと少しの背景知識を使用して、従来の非同期パターンの紛らわしく、多くの場合エラーが発生しやすい詳細をスキップできます。これは、SilverlightのWPFであるWinformsのようなほとんどすべてのイベント駆動型GUIアプリでは非常に貴重です。

47
KeithS

現在受け入れられている答えは誤解を招くものです。 awaitは何も一時停止していません。まず、asyncとマークされたメソッドまたはラムダでのみ使用でき、Taskインスタンスの実行を気にしない場合はvoidまたはTaskを返します。この方法で。

以下に図を示します。

internal class Program
{
    private static void Main(string[] args)
    {
        var task = DoWork();
        Console.WriteLine("Task status: " + task.Status);
        Console.WriteLine("Waiting for ENTER");
        Console.ReadLine();
    }

    private static async Task DoWork()
    {
        Console.WriteLine("Entered DoWork(). Sleeping 3");
        // imitating time consuming code
        // in a real-world app this should be inside task, 
        // so method returns fast
        Thread.Sleep(3000);

        await Task.Run(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("async task iteration " + i);
                    // imitating time consuming code
                    Thread.Sleep(1000);
                }
            });

        Console.WriteLine("Exiting DoWork()");
    }
}

出力:

DoWork()を入力しました。寝ている3
非同期タスクの反復0
タスクステータス:WaitingForActivation
ENTERを待機しています
非同期タスクの反復1
非同期タスクの反復2
非同期タスクの反復3
非同期タスクの反復4
非同期タスクの反復5
非同期タスクの反復6
非同期タスクの反復7
非同期タスクの反復8
非同期タスクの反復9
ExWorking DoWork()

31
Anri

.NETで非同期プログラミングを初めて使用する場合、JavaScript/jQueryを使用した-AJAX呼び出し。単純なjQuery AJAX投稿は次のようになります。

$.post(url, values, function(data) {
  // AJAX call completed, do something with returned data here
});

結果をコールバック関数で処理する理由は、AJAX呼び出しが戻るのを待っている間、現在のスレッドをブロックしないようにするためです。応答が準備できたときのみ、コールバックが起動されます。その間に他のことをするために現在のスレッドを解放します。

JavaScriptがawaitキーワードをサポートしている場合(もちろんサポートしていません( (! )))、これで同じことを達成できます。

var data = await $.post(url, values);
// AJAX call completed, do something with returned data here

それは非常にクリーンですが、同期ブロックコードを導入したように見えます。しかし、(偽の)JavaScriptコンパイラはawaitの後のすべてを取得し、コールバックに配線するため、実行時に2番目の例は最初の例と同じように動作します。

多くの作業を節約しているようには見えないかもしれませんが、例外処理や同期コンテキストなどのことになると、コンパイラは実際にlotを実行していますあなたのための重い持ち上げ。詳細については、 FAQs に続いて Stephen Clearyのブログシリーズ をお勧めします。

10
Todd Menier