Asynchrone Programmierung mit Async und Await in C# 5 unter der Lupe



Ähnliche Dokumente
Async und Await Asynchrone Programmierung in C# 5

.NET Task Parallel Library: Eine Rundtour

Thomas Claudius Huber. Asynchrone Programmierung mit C#

Einfache Arrays. Annabelle Klarl. Einführung in die Informatik Programmierung und Softwareentwicklung

Einführung in die Programmierung

Übung 1 mit C# 6.0 MATTHIAS RONCORONI

Objektorientierte Programmierung

Software Engineering. Zur Architektur der Applikation Data Repository. Franz-Josef Elmer, Universität Basel, HS 2015

Softwarelösungen: Versuch 4

Zählen von Objekten einer bestimmten Klasse

Systeme 1. Kapitel 6. Nebenläufigkeit und wechselseitiger Ausschluss

Einführung in die Programmierung

Java Kurs für Anfänger Einheit 4 Klassen und Objekte

Testen mit JUnit. Motivation

Typumwandlungen bei Referenztypen

Große Übung Praktische Informatik 1

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Java Kurs für Anfänger Einheit 5 Methoden

Neue Features in C# 2.0

Programmierkurs Java

Integrierte und automatisierte GUI-Tests in Java

Software Engineering Interaktionsdiagramme

Tagesprogramm

SEP 114. Design by Contract

Algorithmen und Datenstrukturen

Graphic Coding. Klausur. 9. Februar Kurs A

Einführung in die Java- Programmierung

Daniel Warneke Ein Vortrag im Rahmen des Proseminars Software Pioneers

Monitore. Klicken bearbeiten

Technische Hochschule Georg Agricola WORKSHOP TEIL 3. IKT (Informations- und Kommunikationstechnik) an einer MorseApp erklärt

Delegatesund Ereignisse

Unsere Webapplikation erweitern

Client-Server-Beziehungen

Erstellen und Bearbeiten von Inhalten (Assets)

Dieses Tutorial gibt eine Übersicht der Form Klassen von Struts, welche Besonderheiten und Unterschiede diese aufweisen.

Verhindert, dass eine Methode überschrieben wird. public final int holekontostand() {...} public final class Girokonto extends Konto {...

Erweiterung der Aufgabe. Die Notenberechnung soll nicht nur für einen Schüler, sondern für bis zu 35 Schüler gehen:

Java Virtual Machine (JVM) Bytecode

Objektorientierte Programmierung

Ich liebe Java && Ich liebe C# Rolf Borst

Grundlagen der Programmierung Prof. H. Mössenböck. 3. Verzweigungen

Grundlagen der höheren Mathematik Einige Hinweise zum Lösen von Gleichungen

Programmiervorkurs WS 2012/2013. Schleifen und Methoden

C# im Vergleich zu Java

Grundlagen der Programmierung Prof. H. Mössenböck. 14. Schrittweise Verfeinerung

Java 7. Elmar Fuchs Grundlagen Programmierung. 1. Ausgabe, Dezember 2011 JAV7

S7-Hantierungsbausteine für R355, R6000 und R2700

Übungen zu Einführung in die Informatik: Programmierung und Software-Entwicklung: Lösungsvorschlag

Sichtbarkeit & statische Methoden. Einsatz von Sichtbarkeit Einsatz statischer Methoden programmatische Realisierung 2 Beispielaufgaben

Automatisches Parallelisieren

Prüfung Computation, Programming

2A Basistechniken: Weitere Aufgaben

Übungen zu Softwaretechnik

Einführung in die Programmierung (EPR)

Programmieren in Java

C++ Tutorial: Timer 1

AUSBILDUNG eines OBEDIENCE HUNDES

Erwin Grüner

Einführung in die C++ Programmierung für Ingenieure

Step by Step Softwareverteilung unter Novell. von Christian Bartl

Matrix42. Use Case - Sicherung und Rücksicherung persönlicher Einstellungen über Personal Backup. Version September

Anleitung für die Teilnahme an den Platzvergaben "Studio II, Studio IV und Studio VI" im Studiengang Bachelor Architektur SS15

Software- Handbuch

Dokumentation für Popup (lightbox)

Das Modul ARTIKEL-BARCODE ermöglicht den Druck von Barcode-Etiketten der EAN-Codes 8 und 13.

Java: Vererbung. Teil 3: super()

WPF Steuerelemente Listbox, ComboBox, ListView,

10.6 Programmier-Exits für Workitems

Übersicht Programmablaufsteuerung

Studentische Lösung zum Übungsblatt Nr. 7

Programmiervorkurs SS 2011 Technische Universität Darmstadt Jan Hendrik Burdinski, Felix Kerger

Einführung in die Programmierung für Wirtschaftsinformatik

Universität Karlsruhe (TH)

Prof. Dr. Uwe Schmidt. 21. August Aufgaben zur Klausur Objektorientierte Programmierung im SS 2007 (IA 252)

Programmierung in C. Grundlagen. Stefan Kallerhoff

IT-SICHERHEIT IM UNTERNEHMEN Mehr Sicherheit für Ihre Entscheidung

MCRServlet Table of contents

Kontrollstrukturen und Funktionen in C

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Anleitung zum Prüfen von WebDAV

Viele Bilder auf der FA-Homepage

5 DATEN Variablen. Variablen können beliebige Werte zugewiesen und im Gegensatz zu

Deklarationen in C. Prof. Dr. Margarita Esponda

Python Programmierung. Dipl.-Ing.(FH) Volker Schepper

Die Java Stream API. Funktionale Programmierung mit der Stream API des JDK 1.8. Prof. Dr. Nikolaus Wulff

U08 Entwurfsmuster (II)

5. Tutorium zu Programmieren

Constraint-Algorithmen in Kürze - Mit der Lösung zur Path-Consistency-Aufgabe 9

Kapitel MK:IV. IV. Modellieren mit Constraints

Software-Engineering und Optimierungsanwendungen in der Thermodynamik

EndTermTest PROGALGO WS1516 A

Praktikum zu Einführung in die Informatik für LogWiIngs und WiMas Wintersemester 2015/16. Vorbereitende Aufgaben

Einführung in die Informatik: Programmierung und Software-Entwicklung, WS 14/15. Kapitel 11. Fehler und Ausnahmen 1

Erfolgreiche Verbindung. 3. Anmeldung: Bitte geben Sie Ihren Benutzernamen und Ihr Kennwort ein.

Würfelt man dabei je genau 10 - mal eine 1, 2, 3, 4, 5 und 6, so beträgt die Anzahl. der verschiedenen Reihenfolgen, in denen man dies tun kann, 60!.

Technische Dokumentation SilentStatistikTool

DST EINFÜHRUNG IN MRT (V2)

Anleitung zum Importieren, Durchführen und Auswerten von Umfragen in Blackboard

Benutzerhandbuch DesignMaster II

Vererbung & Schnittstellen in C#

Transkript:

Asynchrone Programmierung mit Async und Await in C# 5 unter der Lupe Prof. Dr. Luc Bläser Hochschule für Technik Rapperswil Parallel 2013, Karlsruhe 16. Mai 2013

Ausgangslage Async/Await Sprachkonstrukte Institutionalisiert in C# 5 (und VB.NET) Basierend auf Task Parallel Library (TPL) in.net 4.5/WinRT First-Class asynchrones Programmiermodell Substanziell anders als gewöhnliche asynchrone Aufrufe Diverse Besonderheiten und Fallstricke async Task CalculateAsync() { Task t = CalculateAsync(); await t; free icon from wikimedia.org

Überblick Async/Await Funktionsweise Ausführungsmodell Fallstricke Architekturüberlegungen Schlussfolgerung

Asynchrone Programmierung: Zweck Methoden nebenläufig zum Aufrufer ausführen Aufrufer soll nicht unnötig blockiert werden Bei I/O Calls, Service Aufrufe, Berechnungen Unnötig blockierend int result = LongOperation(); OtherWork(); Process(result); Könnte parallel zu LongOperation() laufen Erst hier muss LongOperation() fertig sein

Klassische Asynchronität mit TPL Task<int> task = Task.Factory.StartNew<int>(LongOperation); OtherWork(); int result = task.result; Warte auf Task-Ende Caller Thread Start TPL Thread In Task auslagern OtherWork() Wait LongOperation() (return) Task-Ende Alternative: Task ruft «Completion Callback»/Folgearbeit nach Beendigung selber auf

Asynchronität mit Async/Await Async Methode public async Task<int> LongOperationAsync() { Task<int> task = LongOperationAsync(); OtherWork(); int result = await task; Warte auf Beendigung der Async Methode

Async und Await Schlüsselwort async für Methode Aufrufer ist nicht zwingend während der gesamten Ausführung der Async Methode blockiert Mögliche Rückgabetypen void: «fire-and-forget» Task: Keine Rückgabe, aber erlaubt Warten auf Ende Task<T>: Für Methode mit Rückgabetyp T Keine ref oder out Parameter Schlüsselwort await für Tasks Warte auf Ende eines TPL Tasks (sog. Awaiter ) Liefert Resultat des Tasks (sofern Rückgabetyp definiert)

Beispiel: Async Methode Rückgabetyp string Suffix Async als Namenskonvention async Task<string> ConcatWebSitesAsync(string url1, string url2) { HttpClient client = new HttpClient(); Task<string> download1 = client.getstringasync(url1); Task<string> download2 = client.getstringasync(url2); string site1 = await download1; string site2 = await download2; return site1 + site2; Direkte Rückgabe des String async Task<string> GetStringAsync(string url)

Spezielle Regeln async Methode Muss await enthalten => Sonst Compiler-Warnung await Anweisung Nur in async Methode erlaubt => Sonst Compiler-Fehler Grund: Spezielles Ausführungsmodell

Ausführungsmodell Async Methode läuft teilweise synchron, teilweise asynchron Aufrufer führt Methode solange synchron aus, bis ein blockierendes await anliegt Danach läuft die Methode asynchron async Task<int> GetSiteLengthAsync(string url) { HttpClient client = new HttpClient(); Task<string> task = client.getstringasync(url); string site1 = await task; return site1.length; Synchron (Aufrufer Thread) Asynchron (evtl. anderer Thread)

Mechanismus Compiler zerlegt Methode in Abschnitte Erster Abschnitt vor Await: Synchron durch Aufrufer Abschnitt nach Await: Läuft später nach Task-Ende («Continuation») Synchron durch Aufrufer async Task OpAsync() { Task t = OtherAsync(); await t; Asynchron nach Task-Ende

Async Methodenaufruf Methode läuft synchron bis zu blockierenden Await Bei Warten auf anderen Thread bzw. externes I/O Bei blockierendem Await Rücksprung zum Aufrufer Aufrufer Thread Aufruf Rücksprung async Task OpAsync() { Task t = OtherAsync(); await t; Später nach Task-Ende

Abschnitt nach blockierendem Await Fall 1: Aufrufer ohne Synchronisationskontext SynchronizationContext.Current == null Meiste Threads (Konsole, TPL etc.) Abschnitt wird durch Thread des erwarteten Tasks ausgeführt Fall 2: Aufrufer mit Synchronisationskontext Z.B. GUI-Thread Abschnitt wird an diesen Kontext «dispatched» Wird z.b. als Event vom GUI-Thread ausgeführt

Fall 1: Kein Synchronisationskontext Task-Thread führt Abschnitt nach Await aus Aufrufer Thread Aufruf async Task OpAsync() { Task t = OtherAsync(); Task-Start TPL Thread Rücksprung Task t await t; Task-Ende Continuation

Fall 2: Mit Synchronisationskontext Beispiel GUI-Thread als Aufrufer: Dispatch GUI Thread Aufruf async Task OpAsync() { Task t = OtherAsync(); Task-Start TPL Thread Rücksprung Task t Dispatch der Continuation Task-Ende await t;

Wieso diese Komplexität? GUI Frameworks sind Single-Threaded Nur dedizierter UI Thread darf UI-Controls zugreifen Threads können Arbeiten als UI-Events beim UI einreihen UI Thread verarbeitet sukzessive diese UI-Events UI window UI thread Dispatch Event Event Event get execute UI control

Klassische UI-Programmierung void startcalculationbutton_click() { new Thread(LongCalculation).Start(); void LongCalculation() { calculation Dispatcher.BeginInvoke(new Action(() => { resultlabel.content = ; )); _Click() Langlaufende Operation an Thread outsourcen Fremder Thread darf UI nicht zugreifen => Dispatch zu UI UI Thread Worker Thread LongCalculation() Content = BeginInvoke()

Nicht-Blockierende UIs Klassisch: Zerstückelung der Logik Kette von Dispatch (UI Thread/fremder Thread) Hilfsklasse BackgroundWorker Leserlicher Code mit Async/Await Logik in einem Guss (eine Methode) Zerstückelung in mehrere UI-Events hinter Kulissen

UI mit Async/Await async void startcalculationbutton_click() { await LongCalculationAsync(); resultlabel.content = ; async Task LongCalculationAsync() { start and await calculation task UI Thread _Click() TPL Thread calculation task Content = Dispatch

Async/Await Sequenz async void startdownload_click() { API bietet diverse HttpClient client = new HttpClient(); async Methoden foreach (var url in collection) { var data = await client.getstringasync(url); textarea.content += data; UI Thread _Click() TPL Thread Dispatch Http Client Task 1 Content = TPL Thread Dispatch Http Client Task 2 Content =

Tipps zu Async/Await (1) async Methode in synchroner Methode aufrufen task.wait() oder task.result void Test() { Task mytask = LongOpAsync(); mytask.wait(); async Lambda async () => { await SomeOpAsync();

Spezialfall configureawait(false) unterbindet Dispatch an Synchronisationskontext Verhalten wie ohne Synchronisationskontext async void button_click() { Task t = CalculationAsync().configureAwait(false); await t; UI Thread Anderer Thread

Achtung Fallstricke 1. Async Methoden sind nicht per se asynchron 2. Thread-Wechsel innerhalb Methode 3. Quasi-Parallelität der UI-Event-Handler 4. Race Conditions bleiben möglich 5. UI-Deadlocks wegen Async Task-Zugriff 6. Exceptions werden teilweise ignoriert 7. Frühzeitiger Abbruch von «Fire-And-Forget»

Pitfall 1 Async Methoden sind nicht per se asynchron public async Task<bool> IsPrimeAsync(long number) { for (long i = 2; i <= Math.Sqrt(number); i++) { if (number % i == 0) { return false; return true; Läuft vollständig synchron Aufrufer ist während gesamter Ausführung blockiert Compiler-Warnung: kein Await in Async Methode

Pitfall 1: Workaround Rechenintensive Operation explizit als Task ausführen public async Task<bool> IsPrimeAsync(long number) { return await Task.Run(() => { for (long i = 2; i <= Math.Sqrt(number); i++) { if (number % i == 0) { return false; return true; );

Pitfall 1: Diskussion Muss situativ explizit Task in async lancieren Um Asynchronität zu erhalten Compiler-Warnung ist nicht hinreichend public async Task ComputeAsync() { var result = VeryLongCalculation(); await UploadResultAsync(result); Läuft immer noch auf Kosten des Aufrufers Keine Compiler-Warnung

Pitfall 2 Thread-Wechsel innerhalb Methode Falls kein UI / Synchronisationkontext mit Dispatcher public async Task BlockingOperation() { Console.WriteLine("BEFORE "+ Thread.CurrentThread.ManagedThreadId); HttpClient client = new HttpClient(); Task<string> task = client.getstringasync("..."); string result = await task; Console.WriteLine("AFTER " + Thread.CurrentThread.ManagedThreadId); Partielle Nebenläufigkeit berücksichtigen Achtung bei Thread-lokalen Variablen BEFORE 10 AFTER 14

Pitfall 3 Quasi-Parallelität der UI-Event-Handler Im UI: Bei jedem Await können natürlich andere UI-Events dazwischen laufen async void startdownload_click() { User-Click dazwischen => HttpClient client = new HttpClient(); collection evtl. verändert foreach (var url in collection) { var data = await client.getstringasync(url); textarea.content += data; Muss Interferenzen unterbinden - Snapshots / Isolation von anderen Events - Zwischenevent-Ausführung einschränken

Pitfall 4 The async-based approach to asynchronous programming is preferable to existing approaches in almost every case. In particular, this approach is better [] because the code is simpler and you don't have to guard against race conditions - http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx Race Conditions bleiben natürlich möglich! Abschnitt nach await läuft potentiell parallel zum Aufrufer Falls ohne Synchronisationkontext (z.b. kein UI-Thread) Falls configureawait(false) Explizite gestartete Task (Task.Run(), Threads etc.)

Pitfall 4: Race Condition OpAsync(); result = 0; Aufrufer Thread Aufruf Rücksprung Data Race async void OpAsync() { Task t = OtherAsync(); result = await t; Task t Task Thread

Pitfall 5 UI-Deadlocks Aufruf von Task.Wait() oder Task.Result in UI-Thread void calculationbutton_click() { Task<string> task = CalculateAsync(); label.content = task.result; Implizites Task.Wait() => Blockiert UI Thread Deadlock async Task<string> CalculateAsync() { return await Task.Run(); Abschnitt nach await kann nicht laufen, weil UI-Thread blockiert ist

Pitfall 5: Analyse task = CalcAsync(); Task.Result blockiert UI Thread Aufruf Rücksprung async void CalcAsync() { Task t = Task.Run(); Task t Task Thread Wartet auf Methodenende Dispatch Wartet auf UI-Thread return await t;

Pitfall 6 Exceptions werden unter Umständen ignoriert Aufrufer ohne Synchronisationskontext Für async void Methoden Für async Methoden ohne await/wait/result-abfrage void button_click() { LongCalculationAsync().ConfigureAwait(false); async Task LongCalculationAsync() { await Task.Run(() => { ); throw new Exception("TEST"); Exception wird ignoriert

Pitfall 6: Analyse Exceptions werden nur bei Task-Zugriff propagiert Seit 4.5 werden Exceptions in verwaisten Tasks ignoriert Vorher per Garbage Collector ausgelöst TaskScheduler.UnobservedTaskException Event zum Abfangen

Pitfall 7 «Fire-and-Forget» Async-Methode läuft unter Umständen nicht fertig Main-Methode ist fertig und keine sonstige «normalen» (Foreground) Threads laufen static void Main() { ComputeAsync(); async void ComputeAsync() { Task task = Task.Run(); Console.WriteLine(await task); Eventuell nicht mehr ausgeführt

Pitfall 7: Hintergrund TPL Thread Pool benutzt Background-Threads Erlauben jederzeit Programm-Beendigung Programm läuft, solange es Foreground-Threads gibt Main() fertig Aufrufer Thread Aufruf Rücksprung async void ComputeAsync() { Task t = Task.Run(); TPL Thread Programm ist fertig (keine Foreground Threads) Background TPL-Thread abgebrochen

Pitfall 7: Lösung Auf Ende von Async-Methoden warten «Normaler» Foreground Thread existiert, solange Background Thread läuft static void Main() { Task t = ComputeAsync(); t.wait(); async Task ComputeAsync() {

Architekturüberlegungen (1) Eine Async-Methode => Zwei Aufruffälle Mit und ohne Synchronisationskontext Zwei unterschiedliche Verhalten => beides testen Viraler Effekt: async/await-aufrufer wird auch async Unnötig komplexe Methodensignaturen mit Tasks Kosten wegen interner Methodenzerstückelung Synchrone/asynchrone Verwendung sollte meist orthogonal sein «Caller» sollte entscheiden, nicht «Callee» => Risiko von unnötig hoher Komplexität

Architekturüberlegungen (2) Primär im UI Layer sinnvoll Muss aber Zerstückelungs-Mechanismus verinnerlichen Sowieso meist Top-Layer in Architektur In darunterliegenden Layer weniger Limitiert auf inhärent blockierenden Operationen (I/O) Appellation an Caller, asynchrones Design zu wählen Problematisch, wenn Methoden ad-hoc async werden Nebenläufigkeit/Verzahnung kommt ins Spiel Aufrufer kann sowieso leicht eine gewöhnliche Methode asynchron aufrufen (Task.Run())

Unterschiedliche Auffassungen MS Ansatz: «Bottom-Up» Async-Design Schon einfache blockierende Methoden sind async Direkte / indirekte Aufrufer werden auch async Aufrufer muss auf Wunsch selber synchron machen Empfehlung: «Top-Down» Async-Design Kleine Methoden / in Basislayers eher synchron designen Top-Level Methoden bei Bedarf asynchron machen Async-Komplexität auf Top-Level beschränkt

Schlussfolgerungen Komplizierter Mechanismus Anders als gewöhnliche asynchrone Programmierung Genaues Verständnis unabdingbar Diverse Fallstricke Wohlüberlegter Einsatz Primär für UI-Layer angemessen Sonst schnell hohe Komplexität

Danke für Ihr Interesse.NET Concurrency Industriekurse http://concurrency.ch/training Kontakt Prof. Dr. Luc Bläser HSR Hochschule für Technik Rapperswil IFS Institut für Software Rapperswil, Schweiz lblaeser@hsr.ch http://ifs.hsr.ch http://concurrency.ch