Spartakiade 2016: Asynchrone Programmierung
- Posted in:
- Spartakiade
- asynchron
Das Event
Die Spartakiade fand zum 5 Mal statt (ich war zum vierten Mal dabei, glaube ich). Sie wurde toll organisiert: Es gab genug und gut zu essen und trinken, das WLAN funktioniert einwandfrei – damit waren die Grundbedürfnisse von Entwicklern gedeckt :). Wir waren wieder bei Immobilien Scout untergebracht. Die Spartakiade war schnell ausgebucht und sehr gut besucht. Die Stimmung war engagiert, die Leute waren gut drauf. Es macht Spaß an dem Event teilzunehmen.
Der Workshop
Ich habe mir Asynchrone Programmierung bei Daniel Marbach ausgesucht, da ich in diesem Thema ein Novize bin und es an vielen Stellen Einzug hält, auch (oder insbesondere) bei Webanwendungen. Daniel argumentierte, dass asynchroner Code in Zukunft überall Einzug halten wird, fast jede Library wird mittlerweile asynchron geschrieben. Hier findet man den Quellcode zum Workshop: https://github.com/danielmarbach/async-dolls
In .NET arbeitet man mit der TPL (Task Parallel Library). Die Bausteine - die Tasks - werden durch einen Task Scheduler koordiniert. Ein Task kann unterschiedliche Operationen representieren: IO-bound oder CPU-bound operations. CPU-bound Tasks blockieren worker (je nach CPU-Chip hat man davon mehr oder weniger), während IO-bound Tasks concurrent (nebenläufig) arbeiten können. Wir haben uns im Workshop fast nur mit IO-bound Tasks auseinandergesetzt. In C# werden die Keywords async und await als syntaktischer Zucker bereitgestellt, damit man automagisch mit Zustandsmaschinen arbeiten kann.
Hier ein paar lose weitere Erkenntnisse / Best Practices:
- IO-bound kann Netzwerkkommunikation sein (z.B. TCP), Datenbankabfragen, Filesystem-Anfragen (wobei File-Zugriffe in .NET fast alle synchron programmiert sind).
- sequential: await tasks, concurrent: await Task.WhenAll(tasks)
- Nie async void verwenden, sondern immer Task zurückgeben (sonst bekommt man die Exceptions des inneren Codes nicht zu Gesicht).
- In Backend und Libraries ConfigureAwait(false) verwenden, damit der Context nicht zwischengespeichert werden muss.
- Wenn man synchrone APIs in asynchronem Codepfad aufruft danach leeren Task erstellen:
- return Task.FromResult(0) oder return Task.CompletedTask() (ab .NET Framework 4.6)
- Task.Run().GetAwaiter().GetResult() entpackt Exceptions (sonst sind sie gewrappt in AggregateException)
- besser Task.Run nutzen statt Task.Factory.StartNew, da es dann keines Unwraps bedarf
- Semaphore (Limitierung der concurrency): in .NET SemaphoreSlim verwenden (asynchron implementiert)
- async / await ist nicht threadsicher (könnte von einem Thread angefangen werden und von anderem beendet werden)
- Daher nicht ThreadLocal verwenden, sondern AsyncLocal, falls Zustand gespeichert werden muss.
- Im IoC nicht “per Thread” nutzen.
- Man kann Fire and Forget schreiben, wenn man den Task nicht awaiten möchte: Fire().Ignore() wobei Ignore() einfach eine leere Task-Methode ist.
Wir programmierten in dem zweitägigen Workshop eine Message-Pump it einer Pipeline. Nach und nach implementierten wir die Einzelteile und gelangten zu tieferem Verständnis der asynchronen Programmierung. Hier findet man den Quellcode zum Workshop: https://github.com/danielmarbach/async-dolls. Es war ein fordernder Workshop, aber ich habe viele Erkentnisse gewonnen, die ich hoffetnlich lange genug im Kopf behalte, bis ich das nächste Mal mit asynchronen Methoden zu tun habe.