web-dev-qa-db-ja.com

await vs Task.Wait-デッドロック?

Task.Waitawaitの違いはよくわかりません。

ASP.NET WebAPIサービスには、次の機能に似たものがあります。

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ではなくブロッキング待機を使用すると、なぜこれが問題を引き起こさないのですか?

149
ronag

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

Waitは、タスクが完了するまで同期的にブロックします。そのため、現在のスレッドはタスクが完了するのを待って文字通りブロックされます。一般的なルールとして、「asyncずっと下に」を使用する必要があります。つまり、asyncコードでブロックしないでください。私のブログでは、 非同期コードのブロックがデッドロックを引き起こす方法 の詳細に進みます。

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

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

私の async/await intro が役立つかもしれません。

215
Stephen Cleary

私がさまざまなソースから読んだものに基づいて:

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

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

この記事 も良い読み物です。

0
Ayushmati