web-dev-qa-db-ja.com

.net 4.5の非同期と同期の違い

.Net 4.5の非同期プログラミングについて読んだときに、asyncおよびawaitキーワードを読みました- ここ 次の段落

非同期リクエストの処理

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

大胆な言葉のために、非同期要求が同期要求と同じ時間を処理する方法を理解できませんでしたか?

例:

_public async Task MyMethod()
{
    Task<int> longRunningTask = LongRunningOperation();
    //indeed you can do independent to the int result work here 

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

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

LongRunningOperation()はここでTask<int> longRunningTask = LongRunningOperation();を呼び出す最初の行から実行を開始し、awaitを呼び出すと値を返すことを理解しているため、私の観点からは非同期コードは同期よりも速く、そうですか?

別の質問:

MyMethod()の実行に取り組んでいるメインスレッドは、LongRunningOperation()が完了するまで待機することをブロックしていませんが、スレッドプールに戻って別のリクエストを処理することを理解しています。それを実行するためにLongRunningOperation();に割り当てられた別のスレッドがありますか?

yesの場合、非同期プログラミングとマルチスレッドプログラミングの違いは何ですか?

更新:

コードがそのようになるとしましょう:

_public async Task MyMethod()
    {
        Task<int> longRunningTask = LongRunningOperation();
        //indeed you can do independent to the int result work here 
        DoIndependentWork();
        //and now we call await on the task 
        int result = await longRunningTask;
        //use the result 
        Console.WriteLine(result);
    }

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

この場合、LongRunningOperation()の実行中にDoIndependentWork()が別のスレッドによって実行されますか?

17
Abraham Josef

非同期操作は高速ではありません。非同期的に(つまりawait Task.Delay(10000))または同期的に(つまりThread.Sleep(10000)10秒待つと、同じ10秒かかります。唯一の違いは、最初のスレッドは待機中にスレッドを保持しませんが、2番目のスレッドは待機します

これで、タスクを起動し、すぐに完了するのを待たない場合、同じスレッドを使用して他の作業を行うことができますが、非同期操作の実行を「スピードアップ」しません。

var task = Task.Delay(10000);
// processing
await task; // will complete only after 10 seconds

2番目の質問について:Task.Delay(他の真の非同期操作のように)スレッドを実行する必要がないため、 スレッドはありません です。 Task.Delayは、起動するSystem.Threading.Timerを使用して実装され、実行されるとイベントを発生させます。その間、実行するコードがないため、スレッドは必要ありません。

したがって、MyMethodを実行していたスレッドがawait longRunningTaskに達すると、(longRunningTaskがまだ完了していない限り)解放されます。 ThreadPoolスレッドであった場合、ThreadPoolに戻り、アプリケーション内の他のコードを処理できます。


更新に関しては、フローは次のようになります。

  • MyMethodは処理を開始します
  • LongRunningOperationは処理を開始します
  • DoSomeWorkNeedsExecutionは呼び出しスレッドで実行されます
  • awaitLongRunningOperationに到達したため、ホットタスクが返されます。
  • DoIndependentWorkは同じ呼び出しスレッドによって実行されます(LongRunningOperationはまだ「実行中」であり、スレッドは不要です)
  • awaitMyMethodに到達します。元のタスクが完了した場合、同じスレッドが同期的に続行し、そうでない場合は、最終的に完了するホットタスクが返されます。

したがって、async-awaitを使用しているという事実により、CPUを集中的に実行する作業を同期して待機することをブロックするスレッドを使用することができます。

21
i3arnon

以下の違いを考慮してください。

Thread.Sleep(1000);

そして

await Task.Delay(1000);

両方とも実行に1秒かかります。ただし、前者の場合、現在のスレッドはブロックされ(そのリソースはすべて役に立たなくなります)、後者の場合、現在のスレッドは有用な何か他のことを行うことができます(たとえば、別のリクエストを処理します)。

非同期性とは、命令の個々のシーケンスを高速化することではなく、同期コードがブロックする場合に実行できることです。

Re。 別の質問

解放されたスレッドは他のものに使用されます。操作が完了するまで、スレッドは割り当てられません。これは、基になるOS自体が非同期であるため可能です。上記の例では、内部で停止したスレッドではなく、スレッドが解放されたときにスレッドがピックアップするように通知されるタイマーが使用されています。

5
Richard

(I3arnonの答えに基づいて構築)

同期操作とasync-awaitを使用する操作が全体的に同じ時間がかかるということは絶対に真実ではありません。

async-awaitには、いくつかの追加のロジックが含まれています。完了した待機者と状態マシンのチェックが含まれます。これにより、一部の非同期操作は対応する同期操作よりも時間がかかります。

一方、async-awaitに適したほとんどの操作は自然に非同期であり、ルックアンドフィールを同期させるためにいくつかの余分な処理が含まれます。これらの場合、非同期操作は同期操作よりも時間がかかりません。

質問の引用は、Webアプリケーションに関連しています。 Webアプリケーションの場合、非同期操作とは、各リクエストを数マイクロ秒節約することよりも、許容可能な時間内に最大数のリクエストを処理することです。一方、コンテキストの切り替えが含まれる場合は、時間がかかります。そのため、WebアプリケーションでTask.Runを使用すると、アプリケーションにとって良いことよりも悪いことの方が多くなります。

async-awitの詳細については、 my async-awit curation の記事をご覧ください。

2
Paulo Morgado