242

Task.Waitとの違いがよくわかりませんawait

ASP.NETWebAPIサービスの次の関数に似たものがあります。

public class TestController : ApiController
{
    public static async Task<string> Foo()
    {
        await Task.Delay(1).ConfigureAwait(false);
        return "";
    }

    public async static Task<string> Bar()
    {
        return await Foo();
    }

    public async static Task<string> Ros()
    {
        return await Bar();
    }

    // GET api/test
    public IEnumerable<string> Get()
    {
        Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());

        return new string[] { "value1", "value2" }; // This will never execute
    }
}

どこでGetデッドロックが発生しますか。

何が原因でしょうか?ブロッキング待機を使用するのではなく、これが問題を引き起こさないのはなぜawait Task.Delayですか?

4

3 に答える 3

335

Waitawait概念的には似ていますが、実際には完全に異なります。

Waitタスクが完了するまで同期的にブロックします。したがって、現在のスレッドは、タスクが完了するのを待って文字通りブロックされます。原則として、「asyncずっと下まで」を使用する必要があります。つまり、asyncコードをブロックしないでください。私のブログでは、非同期コードでのブロッキングがどのようにデッドロックを引き起こすかについて詳しく説明します。

awaitタスクが完了するまで非同期で待機します。これは、現在のメソッドが「一時停止」され(その状態がキャプチャされ)、メソッドが不完全なタスクを呼び出し元に返すことを意味します。その後、await式が完了すると、メソッドの残りの部分が継続としてスケジュールされます。

Waitまた、「協調ブロック」についても言及されました。これは、実行中のタスクが待機中のスレッドで実行される可能性があることを意味すると思います。これが発生する可能性がある状況もありますが、これは最適化です。タスクが別のスケジューラー用である場合、既に開始されている場合、またはコード以外のタスクである場合(コード例のように:コードがないためにタスクをインラインで実行できない場合)など、発生しない状況は数多くあります。それのための)。WaitDelay

私のasync/awaitイントロが役立つかもしれません。

于 2012-10-30T14:19:07.200 に答える
16

私がさまざまな情報源から読んだものに基づいて:

式は、実行中のawaitスレッドをブロックしません。代わりに、コンパイラーはasync、待機中のタスクの継続としてメソッドの残りの部分をサインアップします。async次に、制御はメソッドの呼び出し元に戻ります。タスクが完了すると、タスクはその継続を呼び出し、asyncメソッドの実行は中断したところから再開します。

シングルが完了するのを待つために、そのメソッドtaskを呼び出すことができます。Task.Waitメソッドを呼び出すとWait、単一のクラスインスタンスの実行が完了するまで、呼び出し元のスレッドがブロックされます。パラメータなしのWait()メソッドは、タスクが完了するまで無条件に待機するために使用されます。Thread.Sleepこのタスクは、メソッドを呼び出して2秒間スリープすることにより、作業をシミュレートします。

この記事もよく読んでいます。

于 2018-12-06T13:52:53.120 に答える
3

いくつかの重要な事実は他の回答では与えられていませんでした:

「非同期待機」はCILレベルではより複雑であるため、メモリとCPU時間がかかります。

待機時間が許容できない場合は、どのタスクもキャンセルできます。

「asyncawait」の場合、そのようなタスクをキャンセルしたり監視したりするためのハンドラーはありません。

Taskの使用は、「非同期待機」よりも柔軟性があります。

同期機能はすべて、非同期でラップできます。

public async Task<ActionResult> DoAsync(long id) 
{ 
    return await Task.Run(() => { return DoSync(id); } ); 
} 

「非同期待機」は多くの問題を引き起こします。ランタイムとコンテキストのデバッグなしでawaitステートメントに到達することはありません。最初に待機が到達しない場合、すべてがブロックされます。場合によっては、待機しているように見えても、すべてがブロックされています。

https://github.com/dotnet/runtime/issues/36063

なぜ同期と非同期のメソッドのコード重複やハックを使用しなければならないのかわかりません。

結論:タスクを手動で作成し、それらを制御する方がはるかに優れています。タスクへのハンドラーは、より多くの制御を提供します。タスクを監視して管理できます。

https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem

英語でごめんなさい。

于 2020-04-20T13:22:36.353 に答える