532 Stimmen

Ist Task.Result dasselbe wie .GetAwaiter.GetResult()?

Ich habe kürzlich Code gelesen, der viele asynchrone Methoden verwendet, aber manchmal müssen sie synchron ausgeführt werden. Der Code macht folgendes:

Foo foo = GetFooAsync(...).GetAwaiter().GetResult();

Ist das dasselbe wie

Foo foo = GetFooAsync(...).Result;

296voto

Nitin Agarwal Punkte 3060

Task.GetAwaiter().GetResult() ist vorzuziehen gegenüber Task.Wait und Task.Result, da es Ausnahmen weiterleitet, anstatt sie in einer AggregateException einzuhüllen. Allerdings führen alle drei Methoden zu möglichen Deadlock- und Threadpool-Problemem. Sie sollten alle vermieden werden zugunsten von async/await.

Das Zitat unten erklärt, warum Task.Wait und Task.Result nicht einfach das Ausnahme-Weiterleitungsverhalten von Task.GetAwaiter().GetResult() enthalten (aufgrund einer "sehr hohen Kompatibilitätsanforderungen").

Wie ich zuvor erwähnt habe, haben wir eine sehr hohe Kompatibilitätsanforderung und daher haben wir Veränderungen vermieden. Daher behält Task.Wait sein Originalverhalten und wickelt immer ein. Es kann jedoch vorkommen, dass Sie sich in fortgeschrittenen Situationen befinden, in denen Sie ein Verhalten ähnlich dem synchronen Blockieren von Task.Wait wünschen, aber Sie möchten, dass die Originalausnahme unverpackt weitergeleitet wird und nicht in einer AggregateException enthalten ist. Um dies zu erreichen, können Sie direkt den Awaiter des Tasks anvisieren. Wenn Sie "await task;" schreiben, übersetzt der Compiler das in die Verwendung der Methode Task.GetAwaiter(), die eine Instanz zurückgibt, die eine Methode GetResult() hat. Beim Verwenden mit einem fehlerhaften Task wird GetResult() die Originalausnahme weiterleiten (so erhält "await task;" sein Verhalten). Sie können also "task.GetAwaiter().GetResult()" verwenden, wenn Sie diese Weiterleitungslogik direkt aufrufen möchten.

https://devblogs.microsoft.com/pfxteam/task-exception-handling-in-net-4-5/

"GetResult" bedeutet eigentlich "prüfe den Task auf Fehler"

Im Allgemeinen versuche ich mein Bestes, um synchron auf eine asynchrone Aufgabe zu warten zu vermeiden. Es gibt jedoch einige wenige Situationen, in denen ich gegen diese Richtlinie verstoße. In diesen seltenen Bedingungen ist meine bevorzugte Methode GetAwaiter().GetResult(), da sie die Task-Ausnahmen beibehält, anstatt sie in einer AggregateException einzuhüllen.

https://blog.stephencleary.com/2014/12/a-tour-of-task-part-6-results.html

250voto

It'sNotALie. Punkte 21449

BEARBEITEN: Dies wurde geschrieben, als ich 13 war, und ist veraltet. Ich empfehle stattdessen die Antwort von Nitin Agarwal.

Ziemlich ähnlich. Ein kleiner Unterschied jedoch: Wenn die Task fehlschlägt, wird GetResult() einfach die direkt verursachte Ausnahme werfen, während Task.Result eine AggregateException werfen wird. Aber was ist der Sinn, eine von beiden zu verwenden, wenn es async ist? Die um 100x bessere Option ist, await zu verwenden.

Außerdem solltest du GetResult() nicht nutzen. Es ist nur für den Compiler gedacht, nicht für dich. Aber wenn du die nervige AggregateException nicht möchtest, nutze es.

77voto

scyuo Punkte 911

https://github.com/aspnet/Security/issues/59

"Eine letzte Bemerkung: Sie sollten vermeiden, Task.Result und Task.Wait so viel wie möglich zu verwenden, da sie immer die innere Ausnahme in einem AggregateException kapseln und die Meldung durch eine generische ersetzen (Ein oder mehrere Fehler sind aufgetreten), was das Debuggen erschwert. Auch wenn die synchrone Version nicht oft verwendet werden sollte, sollten Sie ernsthaft darüber nachdenken, stattdessen Task.GetAwaiter().GetResult() zu verwenden."

46voto

Nuri Tasdemir Punkte 9682

Ein weiterer Unterschied besteht darin, dass, wenn die async-Funktion nur Task anstelle von Task zurückgibt, Sie nicht verwenden können

GetFooAsync(...).Result;

Wohingegen

GetFooAsync(...).GetAwaiter().GetResult();

funktioniert immer noch.

Ich weiß, dass der Beispielcode in der Frage für den Fall Task ist, aber die Frage wird allgemein gestellt.

34voto

Ogglas Punkte 48648

Wie bereits erwähnt, können Sie await verwenden. Wenn Sie den Code synchron ausführen müssen, wie bereits erwähnt .GetAwaiter().GetResult(), .Result oder .Wait(), besteht wie viele in Kommentaren/Antworten gesagt haben, ein Risiko für Deadlocks. Da die meisten von uns Einzeiler mögen, können Sie diese für .Net 4.5< verwenden

Ein Wert über eine Async-Methode abrufen:

var result = Task.Run(() => asyncGetValue()).Result;

Ein Async-Methoden synchron aufrufen:

Task.Run(() => asyncMethod()).Wait();

Es treten keine Deadlock-Probleme aufgrund der Verwendung von Task.Run auf.

Quelle:

https://stackoverflow.com/a/32429753/3850405

Update:

Könnte zu einem Deadlock führen, wenn der aufrufende Thread aus dem Threadpool stammt. Folgendes passiert: Eine neue Aufgabe wird am Ende der Warteschlange eingereiht, und der Thread aus dem Threadpool, der schließlich die Aufgabe ausführen würde, wird blockiert, bis die Aufgabe ausgeführt ist.

Quelle:

https://medium.com/rubrikkgroup/understanding-async-avoiding-deadlocks-e41f8f2c6f5d

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