373 Stimmen

Warum async und return await verwenden, wenn Sie direkt Task<T> zurückgeben können?

Gibt es irgend ein Szenario, in dem das Schreiben einer Methode wie dieser Sinn macht:

public async Task DoSomethingAsync()
{
    // Es könnte hier synchroner Code stehen oder auch nicht... //
    return await DoAnotherThingAsync();
}

anstatt dieses:

public Task DoSomethingAsync()
{
    // Es könnte hier synchroner Code stehen oder auch nicht... //
    return DoAnotherThingAsync();
}

würde Sinn ergeben?

Warum die return await Konstruktion nutzen, wenn man das Task direkt von der inneren DoAnotherThingAsync() Aufruf zurückgeben kann?

Ich sehe überall Code mit return await, ich denke, ich habe etwas übersehen. Aber soweit ich verstehe, wäre es funktional äquivalent, in diesem Fall die async/await Schlüsselwörter nicht zu verwenden und den Task direkt zurückzugeben. Warum zusätzlichen Overhead durch eine weitere await Schicht hinzufügen?

265voto

svick Punkte 224493

Es gibt einen heimtückischen Fall, in dem return in einer normalen Methode und return await in einer async-Methode sich unterschiedlich verhalten: wenn sie mit using kombiniert werden (oder im Allgemeinen mit einem return await in einem try-Block).

Betrachten Sie diese zwei Versionen einer Methode:

Task DoSomethingAsync()
{
    using (var foo = new Foo())
    {
        return foo.DoAnotherThingAsync();
    }
}

async Task DoSomethingAsync()
{
    using (var foo = new Foo())
    {
        return await foo.DoAnotherThingAsync();
    }
}

Die erste Methode wird das Foo-Objekt mit Dispose() aufrufen, sobald die Methode DoAnotherThingAsync() zurückgibt, was wahrscheinlich lange vor ihrer tatsächlichen Fertigstellung geschieht. Das bedeutet, dass die erste Version wahrscheinlich fehlerhaft ist (weil Foo zu früh entsorgt wird), während die zweite Version einwandfrei funktionieren wird.

140voto

Stephen Cleary Punkte 402664

Wenn Sie nicht async benötigen (d. h. Sie können das Task direkt zurückgeben), dann verwenden Sie nicht async.

Es gibt einige Situationen, in denen return await nützlich ist, z. B. wenn Sie zwei asynchrone Operationen durchführen müssen:

var intermediate = await FirstAsync();
return await SecondAwait(intermediate);

Weitere Informationen zur Leistung von async finden Sie in Stephen Toubs MSDN-Artikel und Video zum Thema.

Update: Ich habe einen Blog-Beitrag verfasst, der in viel mehr Detail geht.

29voto

Servy Punkte 197305

Der einzige Grund, warum Sie es tun möchten, ist, wenn es im vorherigen Code ein anderes await gibt oder wenn Sie das Ergebnis auf irgendeine Weise manipulieren, bevor Sie es zurückgeben. Eine weitere Möglichkeit, wie dies geschehen könnte, ist durch einen try/catch, der ändert, wie Ausnahmen behandelt werden. Wenn Sie nichts davon tun, haben Sie recht, es gibt keinen Grund, die Methode async zu machen.

21voto

Andrew Arnott Punkte 77359

Ein weiterer Fall, in dem Sie auf das Ergebnis warten müssen, ist dieser:

async Task GetIFooAsync()
{
    return await GetFooAsync();
}

async Task GetFooAsync()
{
    var foo = await CreateFooAsync();
    await foo.InitializeAsync();
    return foo;
}

In diesem Fall muss GetIFooAsync() auf das Ergebnis von GetFooAsync warten, da der Typ von T zwischen den beiden Methoden unterschiedlich ist und Task nicht direkt in Task zugewiesen werden kann. Aber wenn Sie auf das Ergebnis warten, wird es einfach zu Foo, das direkt in IFoo zugewiesen werden kann. Dann verpackt die async-Methode das Ergebnis einfach in Task und schon kann es losgehen.

21voto

haimb Punkte 321

Wenn Sie return await nicht verwenden, könnten Sie Ihren Stack-Trace beim Debuggen beschädigen oder wenn er in den Logs bei Ausnahmen gedruckt wird.

Wenn Sie die Aufgabe zurückgeben, hat die Methode ihren Zweck erfüllt und ist aus dem Aufrufstack heraus. Wenn Sie return await verwenden, lassen Sie sie im Aufrufstack.

Zum Beispiel:

Aufrufstack bei Verwendung von await: A wartet auf die Aufgabe von B => B wartet auf die Aufgabe von C

Aufrufstack beim Nicht-Verwenden von await: A wartet auf die Aufgabe von C, die B zurückgegeben hat.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X