Best Practices für die asynchrone .NET-Programmierung

Mit der asynchronen Programmierung können Sie ressourcenintensive E / A-Vorgänge ausführen, ohne den Haupt- oder den ausführenden Thread der Anwendung blockieren zu müssen. Obwohl es nützlich und scheinbar einfach zu implementieren ist, birgt es eine Menge Komplexität und Risiken. Zu den potenziellen Risiken, die mit der asynchronen Programmierung verbunden sind, insbesondere die falsche Verwendung der asynchronen Programmierung, wenn die empfohlenen Vorgehensweisen nicht befolgt werden, gehören Deadlocks, Prozessabstürze und sogar eine langsame Leistung. Sie sollten auch das Schreiben und Debuggen von asynchronem Code beherrschen.

Vermeiden Sie bei asynchronen Methoden den Rückgabetyp void

Eine Methode in C # wird mithilfe des Schlüsselworts async in der Methodensignatur zu einer asynchronen Methode. Innerhalb einer asynchronen Methode können ein oder mehrere Schlüsselwörter auf warten warten. Das Schlüsselwort await wird verwendet, um den Aufhängepunkt zu kennzeichnen. Eine asynchrone Methode in C # kann einen der folgenden Rückgabetypen haben: Task, Task und void. Das Schlüsselwort "await" wird in einer asynchronen Methode verwendet, um den Compiler darüber zu informieren, dass die Methode einen Suspendierungs- und Wiederaufnahmepunkt haben kann.

Beachten Sie, dass bei Verwendung der TPL das Äquivalent zur Rückgabe von void in der TPL eine asynchrone Aufgabe ist. Sie sollten sich bewusst sein, dass asynchrone Leere nur für asynchrone Ereignisse verwendet wird und verwendet werden sollte. Wenn Sie es irgendwo anders verwenden, treten Fehler auf. Mit anderen Worten, eine asynchrone Methode mit void als Rückgabetyp wird nicht empfohlen. weil asynchrone Methoden, die void zurückgeben, eine andere Semantik haben, wenn Sie mit Ausnahmen in Ihrer Anwendung arbeiten.

Wenn eine Ausnahme in einer asynchronen Methode mit dem Rückgabetyp Task oder Task auftritt, wird das Ausnahmeobjekt im Task-Objekt gespeichert. Im Gegenteil, wenn Sie eine asynchrone Methode mit einem Rückgabetyp von void haben, ist kein Task-Objekt zugeordnet. Solche Ausnahmen werden im SynchronizationContext ausgelöst, der zum Zeitpunkt des Aufrufs der asynchronen Methode aktiv war. Mit anderen Worten, Sie können Ausnahmen, die in einer asynchronen void-Methode ausgelöst wurden, nicht mit Ausnahmebehandlungsroutinen behandeln, die in der asynchronen Methode geschrieben sind. Asynchrone Methoden mit einem Rückgabetyp von void sind aufgrund dieses Unterschieds in der Fehlerbehandlungssemantik ebenfalls schwierig zu testen. Zu Ihrer Information: Die SynchronizationContext-Klasse im System.Threading-Namespace stellt einen Synchronisationskontext in .Net dar und hilft Ihnen, eine Aufgabe in einen anderen Kontext zu stellen.

Die folgende Codeliste veranschaulicht dies. Sie haben zwei Methoden, nämlich Test und TestAsync, und letztere löst eine Ausnahme aus.

public class AsyncDemo

   {

       public void Test()

       {

           try

           {

               TestAsync();

           }

           catch (Exception ex)

           {

               Console.WriteLine(ex.Message);

           }

       }

       private async void TestAsync()

       {

           throw new Exception("This is an error message");

       }

   }

So können Sie eine Instanz der AsyncDemo-Klasse erstellen und die Testmethode aufrufen.

static void Main(string[] args)

       {

           AsyncDemo obj = new AsyncDemo();

           obj.Test();

           Console.Read();

       }

Die Testmethode ruft die TestAsync-Methode auf und der Aufruf wird in einen Try-Catch-Block eingeschlossen, um die in der TestAsync-Methode ausgelöste Ausnahme zu behandeln. Die in der TestAsync-Methode ausgelöste Ausnahme wird jedoch niemals abgefangen, dh in der Aufrufermethode Test behandelt.

Vermeiden Sie das Mischen von asynchronem und synchronem Code

Sie sollten niemals eine Mischung aus synchronem und asynchronem Code haben. Es ist eine schlechte Programmierpraxis, asynchronen Code durch Aufrufen von Task.Wait oder Task.Result zu blockieren. Ich würde empfehlen, asynchronen Code von Ende zu Ende zu verwenden - dies ist der sicherste Weg, um zu verhindern, dass sich Fehler einschleichen.

Sie können Deadlocks vermeiden, indem Sie verwenden. ConfigureAwait(continueOnCapturedContext: false)wann immer Sie einen Anruf tätigen, um zu warten. Wenn Sie dies nicht verwenden, wird die asynchrone Methode an dem Punkt blockiert, an dem das Warten aufgerufen wurde. In diesem Fall informieren Sie den Kellner lediglich, den aktuellen Kontext nicht zu erfassen. Ich würde sagen, dass es eine gute Praxis ist, .ConfigureAwait (false) zu verwenden, es sei denn, Sie haben einen bestimmten Grund, es nicht zu verwenden.

Ich würde in meinen zukünftigen Blog-Beiträgen hier mehr über asynchrone Programmierung diskutieren. Weitere Informationen zu Best Practices in der asynchronen Programmierung finden Sie in Stephen Clearys großartigem Artikel bei MSDN.