wake-up-neo.com

warten gegen Task.Wait - Deadlock?

Ich verstehe den Unterschied zwischen Task.Wait und await nicht ganz.

Ich habe etwas ähnlich den folgenden Funktionen in einem ASP.NET-WebAPI-Dienst:

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
    }
}

Wo Get Deadlock wird.

Was könnte das bewirken? Warum verursacht dies kein Problem, wenn ich anstelle von await Task.Delay eine blockierende Wartezeit verwende?

135
ronag

Wait und await sind zwar konzeptionell ähnlich - aber tatsächlich völlig unterschiedlich.

Wait wird synchron blockiert, bis die Aufgabe abgeschlossen ist. Der aktuelle Thread ist also buchstäblich blockiert und wartet darauf, dass die Aufgabe abgeschlossen ist. In der Regel sollten Sie "async ganz nach unten" verwenden. Blockieren Sie also nicht den async Code. In meinem Blog gehe ich auf die Details von ein, wie das Blockieren in asynchronem Code Deadlocks verursacht .

await wartet asynchron, bis die Aufgabe abgeschlossen ist. Dies bedeutet, dass die aktuelle Methode "pausiert" ist (ihr Status wird erfasst) und die Methode eine unvollständige Aufgabe an ihren Aufrufer zurückgibt. Später, wenn der Ausdruck await abgeschlossen ist, wird der Rest der Methode als Fortsetzung geplant.

Sie haben auch einen "kooperativen Block" erwähnt, womit Sie eine Aufgabe meinen, die Sie Waitauf dem wartenden Thread ausführen dürfen. Es gibt Situationen, in denen dies passieren kann, aber es ist eine Optimierung. Es gibt viele Situationen, in denen es nicht passieren kann , z. B. wenn die Aufgabe für einen anderen Scheduler bestimmt ist oder wenn sie bereits gestartet wurde oder kein Code ist task (wie in Ihrem Codebeispiel: Wait kann die Task Delay nicht inline ausführen, da kein Code dafür vorhanden ist).

Sie finden möglicherweise mein async/await Intro hilfreich.

229
Stephen Cleary

Basierend auf dem, was ich aus verschiedenen Quellen lese:

Ein await -Ausdruck blockiert den Thread nicht, auf dem er ausgeführt wird. Stattdessen meldet der Compiler den Rest der async-Methode als Fortsetzung der erwarteten Task an. Die Steuerung kehrt dann zum Aufrufer der async-Methode zurück. Wenn die Task abgeschlossen ist, ruft sie ihre Fortsetzung auf und die Ausführung der asynchronen Methode wird dort fortgesetzt, wo sie aufgehört hat.

Um zu warten, bis eine einzelne task abgeschlossen ist, können Sie ihre Task.Wait-Methode aufrufen. Ein Aufruf der Wait-Methode blockiert den aufrufenden Thread, bis die Ausführung der einzelnen Klasseninstanz abgeschlossen ist. Mit der parameterlosen Wait () - Methode wird unbedingt gewartet, bis eine Task abgeschlossen ist. Die Task simuliert die Arbeit, indem sie die Methode Thread.Sleep für zwei Sekunden in den Ruhezustand versetzt.

Dieser Artikel ist auch eine gute Lektüre.

0
Ayushmati