2

注:これは基本的に、私が混乱していることを示していasyncます。多分それは他の混乱した人々を助けることができます.

ループ内でいくつかのHttpClient async awaitリクエストを実行していましたが、リクエストが順番に実行されているように見えることに気付きました (次の反復を開始する前に結果を待機していました)。

await Task.Delayそこで、Web リクエストの代わりに in loopを使用してテストを試みました。

多分私はプロットを失ったかもしれませんがawait、結果が待っている間にループ内でループの次の反復が開始される可能性があると思っていたでしょう。代わりに、すべてが順番に実行されるようです:

int _iterations = 1000;
int _count= 0;
Stopwatch _stopwatch = new Stopwatch();
_stopwatch.Start();                      

for (int i = 0; i < _iterations; i++)
{
    Console.WriteLine("Elapsed: {0}. Calls count: {1}.", _stopwatch.Elapsed, ++_count);
    await Task.Delay(5000);
    Console.WriteLine("Calls count again: {0}", _count);
}

これにより、次の結果が得られます。

Elapsed: 00:00:00.0000059. Calls count: 1.
Calls count again: 1
Elapsed: 00:00:05.0022733. Calls count: 2.
Calls count again: 2
Elapsed: 00:00:10.0100470. Calls count: 3.
Calls count again: 3
Elapsed: 00:00:15.0182479. Calls count: 4.

はい、を省略して、返されたs をいくつかの配列にawait追加し、を使用できます。しかし、それがループ内でブロックされており、すべてが順番に実行されていることに驚いています。これは正常ですか?TaskTask.WhenAllawait

編集:結論として、私はそこで少し混乱しました。でループ外に制御を戻しますawait。これは同期の類推を模倣しているため理にかなっていますが、もちろんスレッドをブロックしません。

4

3 に答える 3

3

これは予期される動作です。しかし、通話がブロックされると言うのは間違いです。使用時にUI スレッドはブロックされませんawait。これは、実際には fork-and-continue のバリエーションです。実行がヒットawaitすると、すぐに呼び出し元に戻り、待機中の呼び出しが終了した後に続行します。

つまり、ある意味では待機しますが、非同期で実行するため、この名前が付けられました。

物事を並行して行いたい場合は、 and を使用して、Task.WhenAll次にTask.WhenAny待機できるようにします。例:

await Task.WhenAll(await DownloadAsync(), await DownloadAsync(), await DownloadAsync());
于 2013-09-30T08:45:02.067 に答える
3

スレッドをブロックしていないことawaitを除いて、コードは通常の同期コードとほとんど同じように見え、動作します。同時に多くのジョブを開始し、それらがすべて終了するのを待ちたい場合はawait、ループの後に移動する必要があります。

次のようなもの (下線付きの識別子がフィールドであると仮定):

async Task PerformIteration()
{
    Console.WriteLine(
        "Elapsed: {0}. Calls count: {1}.", _stopwatch.Elapsed, ++_count);

    await Task.Delay(5000);

    Console.WriteLine("Calls count again: {0}", _count);
}

...

var tasks = new List<Task>();

for (int i=0; i<_iterations; i++)
{
    tasks.Add(PerformIteration());
}

await Task.WhenAll(tasks);

各反復が完了した直後に何かをしたい場合は、別のメソッドが必要です(あなたの場合、2番目のWriteLine())。それが必要ない場合は、 の結果を sTask.Delay()のコレクションに直接追加するだけTaskです。

于 2013-09-30T11:06:00.963 に答える
2

実際にawait Task.Delay(5000)は、あなたのループでブロックされていませんTask.Delay(5000).Wait()。ループは、コンパイラによって生成された継続コールバックを介して 5 秒で再開されますがawait、最初にこのコードを呼び出したメソッドは、ここに入力するとすぐに実行を再開する場合がawaitあります。少し前に同様の質問に答えましたが、参考になるかもしれません。を使用せずに同様のコードをモデル化する方法を示していますawait

于 2013-09-30T08:49:38.600 に答える