Okay, es klingt seltsam, aber der Code ist sehr einfach und erklärt die Situation gut.
public virtual async Task RemoveFromRoleAsync(AzureTableUser user, string role)
{
AssertNotDisposed();
var roles = await GetRolesForUser(user);
roles.Roles = RemoveRoles(roles.Roles, role);
await Run(TableOperation.Replace(roles));
}
(Ich weiß, dass ich in der folgenden Zusammenfassung spreche, aber das Obige ist eine tatsächliche Methode aus dem tatsächlichen Produktionscode, die tatsächlich das tut, worüber ich hier frage, und ich bin tatsächlich daran interessiert, dass Sie sie tatsächlich überprüfen es für die Richtigkeit gegenüber dem Async / Wait-Muster.)
Ich begegne diesem Muster jetzt, wo ich async
/ await
more benutze, immer öfter. Das Muster besteht aus der folgenden Ereigniskette:
- Warten Sie auf einen ersten Anruf, der mir einige Informationen liefert, an denen ich arbeiten muss
- Arbeiten Sie synchron an diesen Informationen
- Warten Sie auf einen letzten Anruf, der die aktualisierte Arbeit speichert
Der obige Codeblock beschreibt normalerweise, wie ich mit diesen Methoden umgehe. Ich habe await
den ersten Anruf, den ich machen muss, weil er asynchron ist. Als Nächstes erledige ich die Arbeit, die ich ausführen muss, die nicht an E / A oder Ressourcen gebunden ist und daher nicht asynchron ist. Schließlich speichere ich meine Arbeit, die auch ein async
Aufruf ist, und aus Frachtkult ich await
es.
Aber ist dies der effizienteste / korrekteste Weg, um mit diesem Muster umzugehen? Mir scheint, ich könnte await
den letzten Anruf überspringen , aber was ist, wenn er fehlschlägt? Und sollte ich eine Task
Methode verwenden, ContinueWith
um meine synchrone Arbeit mit dem ursprünglichen Aufruf zu verketten? Ich bin gerade an einem Punkt angelangt, an dem ich nicht sicher bin, ob ich damit richtig umgehe.
Gibt es angesichts des Codes im Beispiel eine bessere Möglichkeit, diese Aufrufkette für asynchrone / synchrone / asynchrone Methoden zu handhaben?
quelle
Antworten:
Ja, ich denke, das ist der richtige Weg.
Sie können die Sekunde nicht überspringen
await
. Wenn Sie dies tun, scheint die Methode zu früh abgeschlossen zu sein (bevor die Entfernung tatsächlich durchgeführt wurde), und Sie würden nie herausfinden, ob die Entfernung fehlgeschlagen ist.Ich sehe nicht, wie
ContinueWith()
oder so etwas hier helfen würde. Sie könnten es verwenden, um die Verwendung zu vermeidenawait
, aber es würde Ihren Code komplizierter und weniger lesbar machen. Und das ist der springende Punktawait
: das Schreiben von asynchronem Code im Vergleich zur Verwendung von Fortsetzungen zu vereinfachen.quelle
Mit diesem Muster können Sie sicherstellen, dass alle E / A asynchron sind. Synchrone E / A-Methoden bewirken, dass der aktuelle Thread blockiert wird, während er auf eine Antwort vom E / A-Ziel (Netzwerk, Dateisystem usw.) wartet.
Eine andere zu berücksichtigende Sache ist, dass
await
sie verwendet werden sollte, wenn Sie einen Rückgabewert benötigen oder wenn Sie den erwarteten Code benötigen, um fertig zu werden, bevor Sie etwas anderes tun. Wenn Sie keines dieser Dinge benötigen, können Sie Ihre asynchrone Methode mit "feuern und vergessen"Task.Run
.Für die effizienteste Nutzung von Computerressourcen
RemoveRoles
solltenawait RemoveRolesAsync
E / A-RemoveRolesAsync
Vorgänge aktiviert werden, und die von aufgerufenen E / A-Methoden sollten ebenfalls asynchron sein (und möglicherweise abgewartet werden).Wenn die Leistung nicht Ihr größtes Anliegen ist, ist es in Ordnung, synchrone E / A in einem asynchronen Thread auszuführen. Es ist jedoch eine technische Schuld. (In diesem Fall möchten Sie möglicherweise die erste asynchrone Methode mit aufrufen
ConfigureAwait
, je nachdem, wo der Code ausgeführt wird.)Hier finden Sie einen detaillierten Überblick über die Best Practices: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
Hier finden Sie einige Hinweise zum Verhalten von ConfigureAwait in verschiedenen Umgebungen wie ASP.NET, WebAPI usw. - /programming/13489065/best-practice-to-call-configureawait-for-all-server-side -Code
quelle