「async」と「await」をいつどのように使用するか


1065

ことを主な事柄の私の理解1からasyncawait書きやすいコードを作成し、読みすることです-しかし、それらを使用している長時間のロジックを実行するためにバックグラウンドスレッドを産卵に等しいですか?

現在、最も基本的な例を試しています。インラインでコメントを追加しました。はっきりさせてくれませんか?

// I don't understand why this method must be marked as `async`.
private async void button1_Click(object sender, EventArgs e)
{
    Task<int> access = DoSomethingAsync();
    // task independent stuff here

    // this line is reached after the 5 seconds sleep from 
    // DoSomethingAsync() method. Shouldn't it be reached immediately? 
    int a = 1; 

    // from my understanding the waiting should be done here.
    int x = await access; 
}

async Task<int> DoSomethingAsync()
{
    // is this executed on a background thread?
    System.Threading.Thread.Sleep(5000);
    return 1;
}

48
また、上記のコードをコンパイルすると警告が表示されることに注意してください。警告に注意してください。このコードは意味をなさないことを示しています。
Eric Lippert、2013年

回答:


759

使用するasyncawait、コンパイラはバックグラウンドでステートマシンを生成します。

ここで私は私が起こっているいくつかの高レベルの詳細のいくつかを説明できることを望んでいる例です:

public async Task MyMethodAsync()
{
    Task<int> longRunningTask = LongRunningOperationAsync();
    // independent work which doesn't need the result of LongRunningOperationAsync can be done here

    //and now we call await on the task 
    int result = await longRunningTask;
    //use the result 
    Console.WriteLine(result);
}

public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation 
{
    await Task.Delay(1000); // 1 second delay
    return 1;
}

では、ここで何が起こりますか。

  1. Task<int> longRunningTask = LongRunningOperationAsync(); 実行を開始します LongRunningOperation

  2. メインスレッド(スレッドID = 1)にawait longRunningTask到達したと想定して、独立した作業が行われます。

    これで、longRunningTaskが完了しておらず、まだ実行中の場合MyMethodAsync()は、呼び出し元のメソッドに戻るため、メインスレッドはブロックされません。longRunningTaskが完了すると、ThreadPoolのスレッド(任意のスレッド)がMyMethodAsync()以前のコンテキストに戻り、実行を続行します(この場合は、結果をコンソールに出力します)。

2番目のケースは、longRunningTaskがすでに実行を完了していて、結果が利用できる場合です。到達するawait longRunningTaskと、すでに結果が得られているため、コードはまったく同じスレッドで実行され続けます。(この場合、結果をコンソールに出力します)。もちろん、これは上記の例には当てはまりませんTask.Delay(1000)


65
「Task.Delay(1000);」を使用して「待機」する理由 LongRunningOperation非同期メソッドで?
Benison Sam 2015

3
@codea Eric Lippertの記事へのコメントで、彼は紹介記事をこのトピックにリンクし、 DoEvents戦略とasync-awaitを具体的に比較しています
Camilo Martinez

13
@BenisonSamスレッドは少し古いですが、同じ質問があり、答えを探していました。「待機」の理由は、「待機」を省略すると、LongRunningOperationAsync()がすぐに返されるためです。実際、待機を削除すると、コンパイラーは警告を出します。Stephen Clearyのブログ投稿blog.stephencleary.com/2011/09/…は、設計に関する優れた議論を提供しています。
shelbypereira

70
すべてのasyncメソッドが内部にawaitを持つ必要があり、asyncを使用するメソッドでのみawaitを実行できる場合、いつ停止しますか?
Bruno Santos

108
この答えは明らかに間違っています。これらの多くの賛成票は、多くのユーザーに誤った理解を引き起こします。MSのドキュメントには、非同期を使用するだけで他のスレッドは使用されない、ということが明記されています。msdn.microsoft.com/en-us/library/mt674882.aspx誰かが答えを修正してください。これが原因で私は丸一日無駄になりました。
クリシュナディーパック

171

私の理解では、非同期で待機する主なことの1つは、コードの書き込みと読み取りを容易にすることです。

非同期コードを簡単に読み書きできるようにするためです。

長い期間のロジックを実行するためにバックグラウンドスレッドを生成することと同じですか?

どういたしまして。

//このメソッドを「非同期」としてマークする必要がある理由がわかりません。

asyncキーワードが有効にawaitキーワードを。したがって、を使用するメソッドにawaitはすべてマークを付ける必要がありますasync

//この行は、DoSomethingAsync()メソッドから5秒間スリープした後に到達します。すぐに届かないのでは?

いいえ、asyncメソッドはデフォルトでは別のスレッドで実行されないためです。

//これはバックグラウンドスレッドで実行されますか?

番号。


async/ awaitイントロが参考になるかもしれません。MSDN公式ドキュメントも非常に優れており(特にTAPセクション)、asyncチームは優れたFAQを公開しています。


6
そのため、バックグラウンドスレッドでは実行されませんが、ブロックもされません。これは、スレッドとジャグリングする代わりにコールバックを使用する非同期APIにより可能です。(I / O、ソケット、..)操作を開始し、作業に戻ります。操作が完了すると、OSはコールバックを呼び出します。これはNode.jsまたはPython Twistedフレームワークが行うことであり、いくつかの素晴らしい説明もあります。
RomanPlášil2013

3
「asyncキーワードはawaitキーワードを有効にします。したがって、awaitを使用するすべてのメソッドはasyncとマークする必要があります。」-しかし、なぜですか?この回答は、メソッドを非同期としてマークする必要がある理由を理解するのに役立ちません。コンパイラーは、awaitキーワードを探してメソッドが非同期であることを推測できないのでしょうか。
スタニスラフ

9
@Stanislav:その質問に対処するブログエントリがあります。
スティーブンクリアリー2014年

3
推奨される説明:いいえ、asyncメソッドはデフォルトでは別のスレッドで実行されないため。あなたの例では、Sleep()内の呼び出しDoSomethingAsync()は現在のスレッドをブロックし、実行が完了するbutton1_Click()まで実行が続行されないようにDoSomethingAsync()します。Thread.Sleep()が実行中のスレッドをブロックしていることに注意してくださいTask.Delay() does not.
DavidRR

166

説明

以下は、ハイレベルでのasync/の簡単な例awaitです。これ以外にも考慮すべき詳細がたくさんあります。

注:Task.Delay(1000)1秒間の作業をシミュレートします。これは、外部リソースからの応答を待つことと考えるのが最善だと思います。私たちのコードは応答を待っているので、システムは実行中のタスクをサイドにオフに設定し、完了したらそれに戻ることができます。その間、そのスレッドで他の作業を行うことができます。

以下の例では、最初のブロックがまさにそれを行っています。すべてのタスク(Task.Delayライン)をすぐに開始し、それらを脇に置きます。コードはawait a、次の行に進む前に1秒の遅延が完了するまで行で一時停止します。以来bcd、およびeすべてのとほぼ正確に同じ時刻に実行を開始しa(原因のawaitの不足)、彼らは、この場合、ほぼ同じ時刻に終了しなければなりません。

以下の例では、2番目のブロックがタスクをawait開始し、後続のタスクを開始する前にそれが完了するのを待ちます(つまり、何をするか)。これを繰り返すたびに1秒かかります。awaitプログラムを一時停止し、続行する前に、結果を待っています。これが、最初のブロックと2番目のブロックの主な違いです。

Console.WriteLine(DateTime.Now);

// This block takes 1 second to run because all
// 5 tasks are running simultaneously
{
    var a = Task.Delay(1000);
    var b = Task.Delay(1000);
    var c = Task.Delay(1000);
    var d = Task.Delay(1000);
    var e = Task.Delay(1000);

    await a;
    await b;
    await c;
    await d;
    await e;
}

Console.WriteLine(DateTime.Now);

// This block takes 5 seconds to run because each "await"
// pauses the code until the task finishes
{
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
    await Task.Delay(1000);
}
Console.WriteLine(DateTime.Now);

出力:

5/24/2017 2:22:50 PM
5/24/2017 2:22:51 PM (First block took 1 second)
5/24/2017 2:22:56 PM (Second block took 5 seconds)

SynchronizationContextに関する追加情報

注:ここで少しぼやけてしまいます。何か問題がある場合は、修正してください。答えを更新します。これがどのように機能するかを基本的に理解することは重要ですが、を使用しない限り、専門家でなくても問題はConfigureAwait(false)ありませんが、最適化の機会を失う可能性は高いと思います。

これには、async/のawait概念を理解するのがやや難しくなる1つの側面があります。これは、この例では、これがすべて同じスレッド(または少なくとも、に関して同じスレッドのように見えるもの)で発生しているという事実ですSynchronizationContext。デフォルトでawaitは、実行されていた元のスレッドの同期コンテキストを復元します。たとえば、ASP.NETには、HttpContextリクエストが来たときにスレッドに関連付けられるがあります。このコンテキストには、言語、IPアドレス、ヘッダーなどのような元のRequestオブジェクトなど、元のHttpリクエストに固有のものが含まれます。 。処理の途中でスレッドを切り替えると、別のオブジェクトでこのオブジェクトから情報を取得しようとする可能性がありますHttpContextこれは悲惨なことです。コンテキストを何にも使用しないことがわかっている場合は、そのコンテキストを「気にしない」ように選択できます。これにより、基本的に、コンテキストを持たずにコードを別のスレッドで実行できます。

これをどのように達成しますか?デフォルトでは、await a;コードは実際にはコンテキストをキャプチャして復元することを前提としています。

await a; //Same as the line below
await a.ConfigureAwait(true);

メインコードを元のコンテキストなしで新しいスレッドで続行できるようにする場合は、trueではなくfalseを使用するだけで、コンテキストを復元する必要がないことがわかります。

await a.ConfigureAwait(false);

プログラムの一時停止が完了すると、まったく異なるスレッドで異なるコンテキストでプログラムが続行される可能性があります。これは、パフォーマンスの向上によるものです。開始時の元のコンテキストを復元しなくても、利用可能なスレッドで続行できます。

これは混乱しますか?ええ地獄!分かりますか?多分!概念を理解したら、Stephen Clearyの説明に進みます。説明は、async/の技術的理解をawaitすでに持っている人を対象としています。


これらのすべてのタスクがintを返している場合、および最初のタスクの結果を2番目のタスク(またはいくつかの計算)で使用している場合、それは間違いでしょうか?
veerendra gupta 2017

3
@veerendraguptaはい。その場合、それらを非同期で実行しないように意識的に選択します(非同期ではないため)。ここでは説明しませんが、構成コンテキストに関して他に理解しておくべきことがいくつかあります
Joe Phillips

それではawait MethodCall()絶対に無駄ですか?await/をドロップすることもできasyncますか?
Vitani 2018年

2
@Jocieまったく違います。を呼び出すとawait、スレッドを保持するのではなく、プールに戻します。これにより、タスクの戻りを待つ間、他の場所で使用できるようになります
Joe Phillips

2
@JoePhillipsあなたが言ったことは非同期/待機の本質だと思います。呼び出しスレッドは解放され、マシン上の他のプロセスで使用できます。await呼び出しが完了すると、新しいスレッドを使用して、呼び出し元が最初に開始したものを再開します。呼び出し元はまだ待機していますが、その間にスレッドが解放されるという利点があります。それが非同期/待機の利点ですか?
ボブ・ホーン

147

他の答えに加えて、待ってください(C#リファレンス)

含まれている例でより具体的には、それはあなたの状況を少し説明します

次のWindowsフォームの例は、非同期メソッドWaitAsynchronouslyAsyncでのawaitの使用を示しています。そのメソッドの動作をWaitSynchronouslyの動作と比較してください。タスクにawait演算子が適用されていない場合、WaitSynchronouslyは、その定義でasync修飾子を使用し、本体でThread.Sleepを呼び出しているにもかかわらず、同期的に実行されます。

private async void button1_Click(object sender, EventArgs e)
{
    // Call the method that runs asynchronously.
    string result = await WaitAsynchronouslyAsync();

    // Call the method that runs synchronously.
    //string result = await WaitSynchronously ();

    // Display the result.
    textBox1.Text += result;
}

// The following method runs asynchronously. The UI thread is not
// blocked during the delay. You can move or resize the Form1 window 
// while Task.Delay is running.
public async Task<string> WaitAsynchronouslyAsync()
{
    await Task.Delay(10000);
    return "Finished";
}

// The following method runs synchronously, despite the use of async.
// You cannot move or resize the Form1 window while Thread.Sleep
// is running because the UI thread is blocked.
public async Task<string> WaitSynchronously()
{
    // Add a using directive for System.Threading.
    Thread.Sleep(10000);
    return "Finished";
}

3
答えてくれてありがとう。しかし、WaitAsynchronouslyAsync()は別のスレッドで実行されますか?
Dan Dinu 2013年

32
私はそう信じています、セクションからawait式はそれが実行されているスレッドをブロックしません。代わりに、待機中のタスクの継続として、コンパイラーに残りの非同期メソッドを登録させます。その後、制御はasyncメソッドの呼び出し元に戻ります。タスクが完了すると、タスクは継続を呼び出し、asyncメソッドの実行は中断したところから再開します。
Adriaan Stander 2013年

13
このMSDN記事によれば、「asyncキーワードとawaitキーワードによって追加のスレッドが作成されることはありません...非同期メソッドは独自のスレッドでは実行されません」。私の理解では、awaitキーワードでは、フレームワークは(呼び出し側に戻って)スキップして、長い操作が完了するのを待っている間、すべての可能な独立コードを実行できるようにします。つまり、すべての独立したコードが実行された後、長い操作が返されない場合は、ブロックされます。私は今これを学んでいます。
-Vimes

9
@astander不正解です。別のスレッドで実行されませ。継続(メソッドの残りの部分)がスケジュールされ、タイマーがTask.Delay起動したときに呼び出されます。
MgSam 2013年

1
睡眠のため、この答えは間違っています。受け入れられた回答をawait Task.Delay(1000); これは正しい動作です。
Jared Updike、2014

62

上記の説明を簡単なコンソールプログラムで実際に表示する:

class Program
{
    static void Main(string[] args)
    {
        TestAsyncAwaitMethods();
        Console.WriteLine("Press any key to exit...");
        Console.ReadLine();
    }

    public async static void TestAsyncAwaitMethods()
    {
        await LongRunningMethod();
    }

    public static async Task<int> LongRunningMethod()
    {
        Console.WriteLine("Starting Long Running method...");
        await Task.Delay(5000);
        Console.WriteLine("End Long Running method...");
        return 1;
    }
}

そして出力は:

Starting Long Running method...
Press any key to exit...
End Long Running method...

したがって、

  1. Mainは、を介して長時間実行メソッドを開始しTestAsyncAwaitMethodsます。これは、現在のスレッドを停止せずにすぐに戻り、「Press any key to exit」メッセージがすぐに表示されます
  2. すべてこの中には、LongRunningMethodバックグラウンドで実行されています。完了すると、スレッドプールの別のスレッドがこのコンテキストを取得し、最終メッセージを表示します

したがって、スレッドはブロックされません。


「いずれかのキーを押して終了します...」が出力のどの部分に表示されますか?
StudioX 2018年

1
(return 1)の使い方は?必要ですか?
StudioX 2018年

1
@StudioX私はそれが戻り型整数でなければならないと思います
Kuba Do

このreturn 1部分については、awaitもう少し説明に値すると思います。キーワードを使用すると、基になるタイプをTask<T>直接返すことができるため、既存のコードを待機/非同期の世界に簡単に適合させることができます。ただし、戻り値の型を指定せずにを返すことができるため、値を返す必要はありませんTaskこれは、同期voidメソッドと同等です。C#ではasync voidメソッドを使用できることに注意してください。ただし、イベントハンドラーに取り組んでいる場合を除き、そうすることは避けてください。
クリスチャンキス

41

私はあなたが悪い例を選んだと思います System.Threading.Thread.Sleep

asyncタスクのポイントは、メインスレッドをロックせずにバックグラウンドで実行できるようにすることです。DownloadFileAsync

System.Threading.Thread.Sleep 「実行中」ではなく、ただスリープするだけなので、5秒後に次の行に到達します...

この記事を読んでください、それは概念asyncと説明の素晴らしい説明だと思いますawaithttp : //msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx


3
なぜスリープは悪い例ですが、ダウンロードは良い例です。Thread.Sleepを見ると、FooBarのようなもので、時間がかかるタスクがあることを理解しています。彼の質問は関連があると思います
アブドゥルヒム

1
@Abdurrahim Thread.Sleepはスレッドをブロックします(スレッドは他に何もできず、アイドル状態になります)が、非同期メソッドはブロックしません。の場合DownloadFileAsync、リモートサーバーから応答が来るまで、スレッドは他のことを行ったり、実行したりできます。非同期メソッドでの「時間がかかるタスク」のより適切なプレースホルダーはTask.Delay、実際には非同期であるためです。
Gabriel Luci

@GabrielLuci私の異論は遅延と睡眠についてではありません。あなたの答えはわらの答えに似ています。質問に対するコメントとしてこれを置くと、私は異議を唱えることはできませんが、答えとしてはわらの答えのような匂いがします。彼/彼女がしなければならないすべての呼び出しが呼び出しをブロックしている場合でも、そこで非同期を使用しても問題ないと思います。それはすべての目的を無効にすることはありません...残っているものすべてが有効なケースとしてカウントされる構文上の砂糖になります
Abdurrahim

1
これは私の答えではありませんでした。しかし、あなたの要点に対処するには、それはメソッドの目的に依存します。メソッドを呼び出すだけの場合は、成功しました。しかし、この場合、彼は非同期で実行されるメソッドを作成しようとしていました。彼はただasyncキーワードを使ってそれをしました。しかし、彼のメソッドは依然として同期的に実行され、この答えは完全に理由を説明しました。彼が実際に非同期コードを実行しなかったためです。マークされたメソッドは、不完全になるasyncまで同期して実行されます。がない場合、メソッドは同期的に実行され、コンパイラはそのことを警告します。awaitTaskawait
Gabriel Luci

23

以下は、フォローしている人にわかりやすくするための簡単なコンソールプログラムです。TaskToDoこの方法は、あなたが非同期を作りたいというあなたの長時間実行方法です。それを非同期で実行させることはTestAsyncメソッドによって行われます。テストループメソッドは、TaskToDoタスクを実行し、非同期で実行します。実行ごとに同じ順序で完了するわけではないため、結果がわかります。完了すると、コンソールUIスレッドにレポートします。単純ですが、単純な例は、より複雑な例よりもパターンの核心を引き出すと思います。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TestingAsync
{
    class Program
    {
        static void Main(string[] args)
        {
            TestLoops();
            Console.Read();
        }

        private static async void TestLoops()
        {
            for (int i = 0; i < 100; i++)
            {
                await TestAsync(i);
            }
        }

        private static Task TestAsync(int i)
        {
            return Task.Run(() => TaskToDo(i));
        }

        private async static void TaskToDo(int i)
        {
            await Task.Delay(10);
            Console.WriteLine(i);
        }
    }
}

22

最速の学習のために...

  • メソッドの実行フローを理解する(図付き):3分

  • 質問内省(学習酒):1分

  • シンタックスシュガーをすばやく理解する:5分

  • 開発者の混乱を共有する:5分

  • 問題:通常のコードの実際の実装を非同期コードにすばやく変更:2分

  • 次はどこ?

メソッドの実行フローを理解する(図付き):3分

この画像では、#6にのみ焦点を当てます(これ以上はありません) ここに画像の説明を入力してください

#6ステップ:実行が不足したため、ここで実行が停止しました。続行するには、getStringTask(関数の種類)からの結果が必要です。したがって、awaitオペレーターを使用して進行を一時停止し、(このメソッドの)呼び出し元に制御を戻します(yield)。getStringTaskの実際の呼び出しは、#2の前半で行われました。#2では、文字列の結果を返すことが約束されました。しかし、いつ結果が返されますか?私たちは(#1:AccessTheWebAsync)2回目の呼び出しをもう一度行う必要がありますか?#2(ステートメントを呼び出す)または#6(ステートメントを待つ)結果を誰が取得するか

AccessTheWebAsync()の外部呼び出し元も待機しています。したがって、呼び出し元はAccessTheWebAsyncを待機しており、AccessTheWebAsyncは現時点でGetStringAsyncを待機しています。興味深いのは、AccessTheWebAsyncが待機する前にいくつかの作業を行ったことです(#4)。マルチタスクへの同じ自由は、外部の呼び出し元(およびチェーン内のすべての呼び出し元)にも利用でき、これはこの「非同期」の最大の利点です!あなたはそれが同期しているように感じます..または通常ですが、そうではありません。

メソッドがすでに返されていることを思い出してください(#2)。再度返すことはできません(2回目は不可)。では、発信者はどのように知るのでしょうか?それはすべてタスクに関するものです!タスクが渡されました。タスクは待機されました(メソッドではなく、値ではありません)。タスクに値が設定されます。タスクのステータスは完了に設定されます。呼び出し元はタスク(#6)を監視するだけです。したがって、6#は、結果をどこで、誰が取得するかに対する答えです。後でここでさらに読む。

酒を学ぶための質問内省:1分

質問を少し調整してみましょう:

いつどのように使用ますか? asyncawait Tasks

学習Taskは他の2つを自動的にカバーします(そしてあなたの質問に答えます)

シンタックスシュガーをすばやく理解する:5分

  • 変換前(独自の方法)

    internal static int Method(int arg0, int arg1) { int result = arg0 + arg1; IO(); // Do some long running IO. return result; }

  • 上記のメソッドを呼び出すタスク化されたメソッド

    internal static Task<int> MethodTask(int arg0, int arg1) { Task<int> task = new Task<int>(() => Method(arg0, arg1)); task.Start(); // Hot task (started task) should always be returned. return task; }

待機または非同期について言及しましたか?いいえ。上記のメソッドを呼び出すと、監視可能なタスクが取得されます。タスクが何を返すかはすでにわかっています。整数です。

  • タスクの呼び出しは少し注意が必要です。そのとき、キーワードが表示され始めます。MethodTask()を呼び出しましょう

    internal static async Task<int> MethodAsync(int arg0, int arg1) { int result = await HelperMethods.MethodTask(arg0, arg1); return result; }

上記の同じコードが下の画像として追加されました: ここに画像の説明を入力してください

  1. タスクが完了するのを「待っています」。従ってawait
  2. awaitを使用するため、使用する必要がありますasync(必須構文)
  3. Async接頭辞としてのMethodAsync (コーディング標準)

await理解するのは簡単ですが、残りの2つ(asyncAsync)は:)ではない場合があります。まあ、それはコンパイラにとってもっと理にかなっているはずです。

したがって、2つの部分があります。

  1. 「タスク」を作成する
  2. タスクを呼び出す構文糖を作成する(await+async

AccessTheWebAsync()への外部の呼び出し元があり、その呼び出し元も惜しまないことを思い出してください。つまり、同じことが必要await+asyncです。そしてチェーンは続きます。しかし、常にTask一方の端があります。

大丈夫ですが、1人の開発者は#1(タスク)が見つからないことに驚きました...

開発者の混乱を共有する:5分

開発者が実装しないことを間違えましたTaskが、それでも動作します!質問と、ここに記載されている回答のみを理解してください。あなたが読んで完全に理解したことを願っています。要約すると、「タスク」は表示または実装されない可能性がありますが、親クラスのどこかに実装されています。同様に、私たちの例では、すでにビルドされたものを呼び出すMethodAsync()方が、自分でTaskMethodTask())を使用してそのメソッドを実装するよりもはるかに簡単です。ほとんどの開発者はTasks、コードを非同期コードに変換するときに頭を動かすのが難しいと感じています。

ヒント:既存の非同期実装(MethodAsyncまたはなどToListAsync)を見つけて、問題を外部委託してください。したがって、Asyncとawaitを処理するだけで済みます(これは簡単で、通常のコードとかなり類似しています)。

問題:通常のコードの実際の実装を非同期操作にすばやく変更:2分

以下に示すデータレイヤーのコード行が壊れ始めました(多くの場所)。一部のコードを.Net framework 4.2。*から.Net coreに更新したためです。アプリケーション全体で1時間でこれを修正する必要がありました。

var myContract = query.Where(c => c.ContractID == _contractID).First();

簡単!

  1. QueryableExtensionsがあるため、EntityFramework nugetパッケージをインストールしました。換言すれば、それは、私たちはシンプルで非同期実装(タスク)生き残ることができないAsyncawaitのコードで。
  2. 名前空間= Microsoft.EntityFrameworkCore

呼び出しコード行はこのように変更されました

var myContract = await query.Where(c => c.ContractID == _contractID).FirstAsync();
  1. メソッドの署名が変更されました

    Contract GetContract(int contractnumber)

    async Task<Contract> GetContractAsync(int contractnumber)

  2. 呼び出しメソッドも影響を受けました:GetContractAsync(123456);として呼び出されましたGetContractAsync(123456).Result;

  3. 30分で随時交換!

しかし、建築家は、このためだけにEntityFrameworkライブラリを使用しないように私たちに言いました!おっとっと!ドラマ!次に、カスタムタスク実装(yuk)を作成しました。あなたはその方法を知っています。まだ簡単です!..まだまだゆく..

次はどこ?ASP.Net Coreでの同期呼び出しの非同期への変換 について見ることができる素晴らしい簡単なビデオがあります。おそらく、これを読んだ後に進む方向でしょう。


素晴らしい答え!これは私にトンを助けました
cklimowski

1
いい答えだ。(a)「.Netフレームワーク4.2」についての言及(私が知っているようなバージョンは存在しない)(b)EntityFrameWorkのケーシング=> EntityFramework
immitev

15

ここでのすべての回答は、Task.Delay()その他の組み込みasync関数を使用しています。しかし、これらのasync関数を使用しない私の例を次に示します。

// Starts counting to a large number and then immediately displays message "I'm counting...". 
// Then it waits for task to finish and displays "finished, press any key".
static void asyncTest ()
{
    Console.WriteLine("Started asyncTest()");
    Task<long> task = asyncTest_count();
    Console.WriteLine("Started counting, please wait...");
    task.Wait(); // if you comment this line you will see that message "Finished counting" will be displayed before we actually finished counting.
    //Console.WriteLine("Finished counting to " + task.Result.ToString()); // using task.Result seems to also call task.Wait().
    Console.WriteLine("Finished counting.");
    Console.WriteLine("Press any key to exit program.");
    Console.ReadLine();
}

static async Task<long> asyncTest_count()
{
    long k = 0;
    Console.WriteLine("Started asyncTest_count()");
    await Task.Run(() =>
    {
        long countTo = 100000000;
        int prevPercentDone = -1;
        for (long i = 0; i <= countTo; i++)
        {
            int percentDone = (int)(100 * (i / (double)countTo));
            if (percentDone != prevPercentDone)
            {
                prevPercentDone = percentDone;
                Console.Write(percentDone.ToString() + "% ");
            }

            k = i;
        }
    });
    Console.WriteLine("");
    Console.WriteLine("Finished asyncTest_count()");
    return k;
}

2
ありがとうございました!待つのではなく実際にいくつかの作業を行う最初の答え。
Jeffnl

表示してtask.Wait();、非同期/待機を回避するためにそれをどのように使用できるかを感謝します:P
エンコーダー

12

この回答は、ASP.NETに固有の情報を提供することを目的としています。

MVCコントローラーで非同期/待機を利用することで、以下の記事で説明するように、スレッドプールの利用率を高め、はるかに優れたスループットを実現できます。

http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

起動時に多数の同時要求が発生するか、バースト性のある負荷(同時実行性が突然増加する)があるWebアプリケーションでは、これらのWebサービス呼び出しを非同期にすると、アプリケーションの応答性が向上します。非同期リクエストは、同期リクエストと同じ時間で処理されます。たとえば、リクエストが完了するまでに2秒を必要とするWebサービスの呼び出しを行った場合、同期または非同期のどちらで実行されても、リクエストには2秒かかります。ただし、非同期呼び出しの間、スレッドは、最初の要求が完了するのを待つ間、他の要求への応答をブロックされません。したがって、非同期要求は、長時間実行される操作を呼び出す同時要求が多数ある場合に、要求のキューイングとスレッドプールの増加を防ぎます。


12

非同期で単純な説明を待つ

単純なアナロジー

人は朝の電車を待つかもしれませ。これが彼らが現在実行している彼らの主要な仕事であるため、これは彼らがしているすべてです。(同期プログラミング(通常行うこと!))

別の人は、タバコを吸ってからコーヒーを飲む間、朝の電車を待つかもしれません。(非同期プログラミング)

非同期プログラミングとは何ですか?

非同期プログラミングでは、プログラマーがコードの一部をメインの実行スレッドとは別のスレッドで実行し、その完了をメインスレッドに通知することを選択します。

asyncキーワードは実際には何をしますか?

次のようなメソッド名にasyncキーワードをプレフィックスする

async void DoSomething(){ . . .

プログラマが非同期タスクを呼び出すときにawaitキーワードを使用できるようにします。それだけです。

何でこれが大切ですか?

多くのソフトウェアシステムでは、メインスレッドは特にユーザーインターフェイスに関連する操作のために予約されています。コンピューターで完了するまでに5秒かかる非常に複雑な再帰アルゴリズムを実行しているが、これをメインスレッド(UIスレッド)で実行している場合ユーザーがアプリケーションで何かをクリックしようとすると、フリーズしているように見えます私のメインスレッドがキューに入れられており、現在処理している操作が多すぎます。その結果、メインスレッドはマウスクリックを処理してボタンクリックからメソッドを実行することができません。

AsyncとAwaitはいつ使用しますか?

ユーザーインターフェイスに関係のないことを行う場合は、理想的には非同期キーワードを使用します。

たとえば、ユーザーが携帯電話でスケッチできるプログラムを書いているとしますが、5秒ごとにインターネットで天気をチェックしているとしましょう。

アプリケーションのユーザーはモバイルタッチスクリーンを操作してきれいな絵を描く必要があるので、天気予報を得るために5秒ごとにネットワークにポーリングが呼び出されるのを待つ必要があります。

AsyncとAwaitの使い方

上記の例に続いて、これを記述する方法のいくつかの疑似コードを次に示します。

    //ASYNCHRONOUS
    //this is called using the await keyword every 5 seconds from a polling timer or something.

    async Task CheckWeather()
    {
        var weather = await GetWeather();
        //do something with the weather now you have it
    }

    async Task<WeatherResult> GetWeather()
    {

        var weatherJson = await CallToNetworkAddressToGetWeather();
        return deserializeJson<weatherJson>(weatherJson);
    }

    //SYNCHRONOUS
    //This method is called whenever the screen is pressed
    void ScreenPressed()
    {
        DrawSketchOnScreen();
    }

追記-アップデート

元のメモで、C#ではタスクにラップされたメソッドのみを待つことができることを忘れていました。たとえば、このメソッドを待つことができます:

// awaiting this will return a string.
// calling this without await (synchronously) will result in a Task<string> object.
async Task<string> FetchHelloWorld() {..

次のようなタスクではないメソッドを待つことはできません。

async string FetchHelloWorld() {..

ここで Taskクラスのソースコードを確認してください


4
これを書いてくれてありがとう。
Prashant

10

非同期/待機

実際には、Async / Awaitは、非同期タスクのコールバックを作成するためのシンタックスシュガーであるキーワードのペアです。

この操作を例にとります。

    public static void DoSomeWork()
    {
        var task = Task.Run(() =>
        {
            // [RUNS ON WORKER THREAD]

            // IS NOT bubbling up due to the different threads
            throw new Exception();
            Thread.Sleep(2000);

            return "Hello";
        });

        // This is the callback
        task.ContinueWith((t) => {
            // -> Exception is swallowed silently
            Console.WriteLine("Completed");

            // [RUNS ON WORKER THREAD]
        });
    }

上記のコードにはいくつかの欠点があります。エラーは渡されず、読みにくいです。しかし、AsyncとAwaitが私たちを助けるためにやって来ました:

    public async static void DoSomeWork()
    {
        var result = await Task.Run(() =>
        {
            // [RUNS ON WORKER THREAD]

            // IS bubbling up
            throw new Exception();
            Thread.Sleep(2000);

            return "Hello";
        });

        // every thing below is a callback 
        // (including the calling methods)

        Console.WriteLine("Completed");

    }

Await呼び出しは非同期メソッド内にある必要があります。これにはいくつかの利点があります。

  • タスクの結果を返します
  • コールバックを自動的に作成します
  • エラーをチェックし、それらを呼び出しスタックでバブルアップさせます(呼び出しスタックで待機なしの呼び出しまでのみ)
  • 結果を待つ
  • メインスレッドを解放します
  • メインスレッドでコールバックを実行します
  • タスクにはスレッドプールのワーカースレッドを使用します
  • コードを読みやすくする
  • そしてもっとたくさん

:AsyncとAwaitは、これらを行わない非同期呼び出しで使用さます。これにはTask.Run()のようにタスクライブラリを使用する必要があります。

これは、解決策を待っているものとなしの比較です。

これは非同期ではないソリューションです:

    public static long DoTask()
    {
        stopWatch.Reset();
        stopWatch.Start();

        // [RUNS ON MAIN THREAD]
        var task = Task.Run(() => {
            Thread.Sleep(2000);
            // [RUNS ON WORKER THREAD]
        });
        // goes directly further
        // WITHOUT waiting until the task is finished

        // [RUNS ON MAIN THREAD]

        stopWatch.Stop();
        // 50 milliseconds
        return stopWatch.ElapsedMilliseconds;
    }

これは非同期メソッドです:

    public async static Task<long> DoAwaitTask()
    {
        stopWatch.Reset();
        stopWatch.Start();

        // [RUNS ON MAIN THREAD]

        await Task.Run(() => {
            Thread.Sleep(2000);
            // [RUNS ON WORKER THREAD]
        });
        // Waits until task is finished

        // [RUNS ON MAIN THREAD]

        stopWatch.Stop();
        // 2050 milliseconds
        return stopWatch.ElapsedMilliseconds;
    }

実際にはawaitキーワードなしで非同期メソッドを呼び出すことができますが、これはここでの例外がリリースモードで飲み込まれることを意味します。

    public static Stopwatch stopWatch { get; } = new Stopwatch();

    static void Main(string[] args)
    {
        Console.WriteLine("DoAwaitTask: " + DoAwaitTask().Result + " ms");
        // 2050 (2000 more because of the await)
        Console.WriteLine("DoTask: " + DoTask() + " ms");
        // 50
        Console.ReadKey();
    }

AsyncとAwaitは並列コンピューティング用ではありません。メインスレッドをブロックしないようにするために使用されます。asp.netまたはWindowsアプリケーションの場合、ネットワーク呼び出しが原因でメインスレッドをブロックすることは悪いことです。これを行うと、アプリが応答しなくなったり、クラッシュしたりします。

その他の例については、ms docsを確認してください。


9

正直なところ、私は今でも最良の説明はWikipediaの将来と約束についてのものであると考えています:http : //en.wikipedia.org/wiki/Futures_and_promises

基本的な考え方は、非同期にタスクを実行するスレッドの個別のプールがあるということです。それを使うとき。ただし、オブジェクトは、いつか操作を実行し、要求したときに結果を提供することを約束します。これは、結果をリクエストして終了していない場合はブロックされ、それ以外の場合はスレッドプールで実行されることを意味します。

そこから最適化できます。一部の操作は非同期に実装でき、後続のリクエストをバッチ処理したり、並べ替えたりすることで、ファイルIOやネットワーク通信などを最適化できます。これが既にMicrosoftのタスクフレームワークにあるかどうかはわかりませんが、そうでない場合は、最初に追加するものの1つになります。

実際には、C#4.0で、yieldを使用して未来パターンsort-ofを実装できます。それが正確にどのように機能するかを知りたい場合は、まともな仕事をする次のリンクをお勧めしますhttp : //code.google.com/p/fracture/source/browse/trunk/Squared/TaskLib/。ただし、自分でいじってみると、クールなことをすべて実行したい場合は、言語サポートが本当に必要であることに気づくでしょう。これはまさにMicrosoftが行ったことです。


8

同じプログラムでTask、Task.WaitAll()、async、await演算子の使用法を示す簡単なコンソールアプリケーションを実行するには、このフィドルhttps://dotnetfiddle.net/VhZdLU(および可能であれば改善)を参照してください。

このフィドルは、実行サイクルの概念を明確にするはずです。

これがサンプルコードです

using System;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {               
        var a = MyMethodAsync(); //Task started for Execution and immediately goes to Line 19 of the code. Cursor will come back as soon as await operator is met       
        Console.WriteLine("Cursor Moved to Next Line Without Waiting for MyMethodAsync() completion");
        Console.WriteLine("Now Waiting for Task to be Finished");       
        Task.WaitAll(a); //Now Waiting      
        Console.WriteLine("Exiting CommandLine");       
    }

    public static async Task MyMethodAsync()
    {
        Task<int> longRunningTask = LongRunningOperation();
        // independent work which doesn't need the result of LongRunningOperationAsync can be done here
        Console.WriteLine("Independent Works of now executes in MyMethodAsync()");
        //and now we call await on the task 
        int result = await longRunningTask;
        //use the result 
        Console.WriteLine("Result of LongRunningOperation() is " + result);
    }

    public static async Task<int> LongRunningOperation() // assume we return an int from this long running operation 
    {
        Console.WriteLine("LongRunningOperation() Started");
        await Task.Delay(2000); // 2 second delay
        Console.WriteLine("LongRunningOperation() Finished after 2 Seconds");
        return 1;
    }   

}

出力ウィンドウからのトレース: ここに画像の説明を入力してください


3
public static void Main(string[] args)
{
    string result = DownloadContentAsync().Result;
    Console.ReadKey();
}

// You use the async keyword to mark a method for asynchronous operations.
// The "async" modifier simply starts synchronously the current thread. 
// What it does is enable the method to be split into multiple pieces.
// The boundaries of these pieces are marked with the await keyword.
public static async Task<string> DownloadContentAsync()// By convention, the method name ends with "Async
{
    using (HttpClient client = new HttpClient())
    {
        // When you use the await keyword, the compiler generates the code that checks if the asynchronous operation is finished.
        // If it is already finished, the method continues to run synchronously.
        // If not completed, the state machine will connect a continuation method that must be executed WHEN the Task is completed.


        // Http request example. 
        // (In this example I can set the milliseconds after "sleep=")
        String result = await client.GetStringAsync("http://httpstat.us/200?sleep=1000");

        Console.WriteLine(result);

        // After completing the result response, the state machine will continue to synchronously execute the other processes.


        return result;
    }
}

3

より高いレベルでは:

1)Asyncキーワードはawaitを有効にし、それだけです。Asyncキーワードは、別のスレッドでメソッドを実行しません。最初のf asyncメソッドは、時間がかかるタスクで待機するまで同期的に実行されます。

2)TaskまたはタイプTのTaskを返すメソッドを待つことができます。asyncvoidメソッドを待つことはできません。

3)メインスレッドが遭遇した瞬間に時間がかかるタスクで待機するか、実際の作業が開始されると、メインスレッドは現在のメソッドの呼び出し元に戻ります。

4)メインスレッドがまだ実行中のタスクで待機していることを確認した場合、メインスレッドは待機せず、現在のメソッドの呼び出し元に戻ります。このようにして、アプリケーションは応答性を維持します。

5)処理タスクで待機し、スレッドプールとは別のスレッドで実行されるようになりました。

6)この待機タスクが完了すると、その下のすべてのコードが別のスレッドによって実行されます

以下はサンプルコードです。それを実行してスレッドIDを確認してください

using System;
using System.Threading;
using System.Threading.Tasks;

namespace AsyncAwaitDemo
{
    class Program
    {
        public static async void AsynchronousOperation()
        {
            Console.WriteLine("Inside AsynchronousOperation Before AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
            //Task<int> _task = AsyncMethod();
            int count = await AsyncMethod();

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod Before Await, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            //int count = await _task;

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await Before DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            DependentMethod(count);

            Console.WriteLine("Inside AsynchronousOperation After AsyncMethod After Await After DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
        }

        public static async Task<int> AsyncMethod()
        {
            Console.WriteLine("Inside AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
            int count = 0;

            await Task.Run(() =>
            {
                Console.WriteLine("Executing a long running task which takes 10 seconds to complete, Thread Id: " + Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(20000);
                count = 10;
            });

            Console.WriteLine("Completed AsyncMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            return count;
        }       

        public static void DependentMethod(int count)
        {
            Console.WriteLine("Inside DependentMethod, Thread Id: " + Thread.CurrentThread.ManagedThreadId + ". Total count is " + count);
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Started Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            AsynchronousOperation();

            Console.WriteLine("Completed Main method, Thread Id: " + Thread.CurrentThread.ManagedThreadId);

            Console.ReadKey();
        }

    }
}

2

私もそれを理解しているように、ミックスに3番目の用語を追加する必要がありますTask

Async 非同期メソッドであると言うためにメソッドに置く修飾子です。

Taskasync関数の戻り値です。非同期で実行されます。

あなたawaitはタスクです。コードの実行がこの行に達すると、制御は周囲の元の関数の呼び出し元にジャンプして戻ります。

代わりに、async関数の戻り値(つまりTask)を変数に割り当てた場合、コードの実行がこの行に到達すると、非同期的に実行されている、周囲の関数のその行を過ぎて続行します。Task


1

それらを使用して、バックグラウンドスレッドを生成して長時間のロジックを実行するのと同じですか?

この記事MDSN:async and await(C#)を使用した非同期プログラミングは、それを明示的に説明しています。

asyncおよびawaitキーワードを使用しても、追加のスレッドが作成されることはありません。非同期メソッドは独自のスレッドで実行されないため、非同期メソッドはマルチスレッドを必要としません。メソッドは現在の同期コンテキストで実行され、メソッドがアクティブな場合にのみスレッドで時間を使用します。


1

次のコードでは、HttpClientメソッドGetByteArrayAsyncがタスクgetContentsTaskを返します。タスクは、タスクが完了したときに実際のバイト配列を生成することを約束します。getContentsTaskにawaitオペレーターを適用して、getContentsTaskが完了するまでSumPageSizesAsyncでの実行を一時停止します。その間、SumPageSizesAsyncの呼び出し元に制御が戻ります。getContentsTaskが完了すると、await式はバイト配列に評価されます。

private async Task SumPageSizesAsync()
{
    // To use the HttpClient type in desktop apps, you must include a using directive and add a 
    // reference for the System.Net.Http namespace.
    HttpClient client = new HttpClient();
    // . . .
    Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);
    byte[] urlContents = await getContentsTask;

    // Equivalently, now that you see how it works, you can write the same thing in a single line.
    //byte[] urlContents = await client.GetByteArrayAsync(url);
    // . . .
}

1

以下は、ダイアログを開いてExcelファイルを読み取り、非同期を使用して非同期で実行するのを待つコードです。Excelから1行ずつ読み取り、グリッドにバインドするコードです。

namespace EmailBillingRates
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            lblProcessing.Text = "";
        }

        private async void btnReadExcel_Click(object sender, EventArgs e)
        {
            string filename = OpenFileDialog();

            Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
            Microsoft.Office.Interop.Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(filename);
            Microsoft.Office.Interop.Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[1];
            Microsoft.Office.Interop.Excel.Range xlRange = xlWorksheet.UsedRange;
            try
            {
                Task<int> longRunningTask = BindGrid(xlRange);
                int result = await longRunningTask;

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }
            finally
            {
                //cleanup  
               // GC.Collect();
                //GC.WaitForPendingFinalizers();

                //rule of thumb for releasing com objects:  
                //  never use two dots, all COM objects must be referenced and released individually  
                //  ex: [somthing].[something].[something] is bad  

                //release com objects to fully kill excel process from running in the background  
                Marshal.ReleaseComObject(xlRange);
                Marshal.ReleaseComObject(xlWorksheet);

                //close and release  
                xlWorkbook.Close();
                Marshal.ReleaseComObject(xlWorkbook);

                //quit and release  
                xlApp.Quit();
                Marshal.ReleaseComObject(xlApp);
            }

        }

        private void btnSendEmail_Click(object sender, EventArgs e)
        {

        }

        private string OpenFileDialog()
        {
            string filename = "";
            OpenFileDialog fdlg = new OpenFileDialog();
            fdlg.Title = "Excel File Dialog";
            fdlg.InitialDirectory = @"c:\";
            fdlg.Filter = "All files (*.*)|*.*|All files (*.*)|*.*";
            fdlg.FilterIndex = 2;
            fdlg.RestoreDirectory = true;
            if (fdlg.ShowDialog() == DialogResult.OK)
            {
                filename = fdlg.FileName;
            }
            return filename;
        }

        private async Task<int> BindGrid(Microsoft.Office.Interop.Excel.Range xlRange)
        {
            lblProcessing.Text = "Processing File.. Please wait";
            int rowCount = xlRange.Rows.Count;
            int colCount = xlRange.Columns.Count;

            // dt.Column = colCount;  
            dataGridView1.ColumnCount = colCount;
            dataGridView1.RowCount = rowCount;

            for (int i = 1; i <= rowCount; i++)
            {
                for (int j = 1; j <= colCount; j++)
                {
                    //write the value to the Grid  
                    if (xlRange.Cells[i, j] != null && xlRange.Cells[i, j].Value2 != null)
                    {
                         await Task.Delay(1);
                         dataGridView1.Rows[i - 1].Cells[j - 1].Value =  xlRange.Cells[i, j].Value2.ToString();
                    }

                }
            }
            lblProcessing.Text = "";
            return 0;
        }
    }

    internal class async
    {
    }
}

0

ここでの回答は、待機/非同期に関する一般的なガイダンスとして役立ちます。また、await / asyncの接続方法に関する詳細も含まれています。このデザインパターンを使用する前に知っておくべき実践的な経験をいくつかお話ししたいと思います。

「待つ」という用語はリテラルであるため、呼び出すスレッドは、メソッドの結果を待ってから続行します。上のフォアグラウンドスレッド、これは災害。フォアグラウンドスレッドは、ビュー、ビューモデル、初期アニメーションなど、これらの要素でブートストラップしたものを含め、アプリを構築する負担を負います。したがって、フォアグラウンドスレッドを待つときは、アプリを停止します。ユーザーは待機し、何も起こらないように見えます。これは否定的なユーザー体験を提供します。

確かに、さまざまな手段を使用してバックグラウンドスレッドを待つことができます。

Device.BeginInvokeOnMainThread(async () => { await AnyAwaitableMethod(); });

// Notice that we do not await the following call, 
// as that would tie it to the foreground thread.
try
{
Task.Run(async () => { await AnyAwaitableMethod(); });
}
catch
{}

これらの解説の完全なコードは、https://github.com/marcusts/xamarin-forms-annoyancesにあります。AwaitAsyncAntipattern.slnというソリューションを参照してください。

GitHubサイトには、このトピックに関するより詳細なディスカッションへのリンクもあります。


1
私が理解していることからasync / await、コールバックの構文糖は、スレッド化とは何の関係もありません。msdn.microsoft.com/en-us/magazine/hh456401.aspx これは、CPUにバインドされていないコード用であり、たとえば、入力または遅延を待機しています。Task.RunCPUバインドコードblog.stephencleary.com/2013/10/…に
geometrikal

The term "await" is literal, so whatever thread you call it on will wait for the result of the method before continuing.これは真実ではありません-たぶん、あなたはTask.Wait()を意味しましたか を使用するとawait、待機したものがすべて完了したときに実行される継続としてメソッドの残りが設定されます。使用したメソッドを終了するため、呼び出し元は続行できます。次に、待機した行が実際に完了すると、一部のスレッド(通常はワーカースレッド)でそのメソッドの残りの部分が終了します。
Don Cheadle

非常にコアで@geometrikal、async/awaitについてですが解放 .NETスレッドを。あなたの場合はawait(たとえば、.NETのFile.WriteAsyncなど)真に-非同期操作、それはあなたが使用した方法の残りの一時停止awaitにし、その呼び出し側は引き続き、潜在的にその目的を完了することができます。スレッドのブロックやawait-ed操作の待機はありません。await編集した操作が完了すると、async/awaitメソッドの残りの部分がスレッドに配置されて実行されます(コールバックのアイデアと同様)。
Don Cheadle
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.