Web programozás és haladó fejlesztési technikák Task async-await

Slides:



Advertisements
Hasonló előadás
4. alkalom – Hálózat Kezelés
Advertisements

A Windows Azure egy skálázható számításifelhő-platform, amelyet a Microsoft hosztol a világ több pontján lévő adatközpontjaiban. Az Azure egyszerű,
HÁLÓZAT SOAP Hagyományos WCF/ASMX webszervizek.
V 1.0 Szabó Zsolt, Óbudai Egyetem, Haladó Programozás Parallel.For()
Hibakezelés és Tesztelés a Visual Studio.NET-ben
A Windows 7 automatizált telepítése Windows AIK használatával
© Kozsik Tamás Beágyazott osztályok A blokkstrukturáltság támogatása –Eddig: egymásba ágyazható blokk utasítások Osztálydefiníciók is egymásba.
Csala Péter ANDN #4. 2 Tartalom  C# - ban előre definiált típusok  Változók  Változókkal műveletek  Elágazás  Ciklus.
Tanszéki konzulens: Horváth Ákos Készítette: Kóródi Norbert.
UNIVERSITY OF SZEGED D epartment of Software Engineering UNIVERSITAS SCIENTIARUM SZEGEDIENSIS Programozás II. 9. Gyakorlat Alap file műveletek.
UNIVERSITY OF SZEGED D epartment of Software Engineering UNIVERSITAS SCIENTIARUM SZEGEDIENSIS Programozás II. 6. Gyakorlat const, static, dinamikus 2D.
Fejlett Programozási Technológiák II. Világos Zsolt 12. gyakorlat.
Ellenőrző kérdések a)Auto-indexing enabled b)Auto-indexing disabled c)Nem eldönthető 1.
A C++ programozási nyelvSoós Sándor 1/15 C++ programozási nyelv Gyakorlat hét Nyugat-Magyarországi Egyetem Faipari Mérnöki Kar Informatikai Intézet.
WEB Technológiák Dr. Pance Miklós – Kolcza Gábor Miskolci Egyetem.
Krizsán Zoltán iit 1.2.  Nem kell vizuális felületnek lennie.  Delegátumok segítségével valósíthatja meg a.NET. Krizsán Zoltán iit Delegátumok C#-ban2.
Krizsán Zoltán.  Ha az algoritmus sokáig dolgozik,  de el akarjuk kerülni a „fagyást”.  Kisebb a költsége, mint az új folyamatnak.  Programozás szempontjából.
Kliensoldali Programozás
Kivételkezelés.
Kivételkezelés a C++ nyelvben Bevezetés
1 Operációs rendszerek Signal kezelés. 2 SIGNAL kezelés Egyszerű folyamatok közötti kommunikációs (IPC – Inter Process Communication) megoldás. A signal.
P ROGRAMOZÁS C# - BAN Kivételkezelés. P ÉLDA I. Nullával való osztás miatt kapjuk a hibaüzenetet.
Rendelkezésre álló erőforrások pontos ismerete Kiosztott feladatok közel „valósidejű” követése Átláthatóság Tervezési folyamatok támogatása.
1 Szoftvertechnológia alapjai Java előadások Förhécz András, doktorandusz tárgy honlap:
2012. tavaszi félév Vitéz Gergely. A diasor ismerete nem helyettesíti a tankönyvet, és a példatárat. A diasor ismerete szükséges, de nem elégséges feltétele.
1 Hernyák Zoltán Programozási Nyelvek II. Eszterházy Károly Főiskola Számítástudományi tsz.
Hernyák Zoltán Programozási Nyelvek II.
1 Hernyák Zoltán Web: Magasszintű Programozási Nyelvek I. Eszterházy.
Javascript Microsoft által készített kiegészítése Statikus típusosság Nagy projektek Windows 8 fejlesztésénél WinRT egy részét ebben írták Nyílt forráskódú,
Web Architecture. Development of Computing Architectures Monolithic mainframe programming Client Server Real Client Server Web Programming.
Java programozási nyelv Filekezelés
Java programozási nyelv Metódusok
Java programozási nyelv Adatbekérés konzolról
Generics Krizsán Zoltán. Bemutató A.NET 2.0 verziótól. A.NET 2.0 verziótól. Típusparaméter Típusparaméter Más nyelvben ez a template (sablon). Más nyelvben.
A Visual Basic nyelvi elemei
Power Lutár Patrícia Pellek Krisztián.  -ltLess than  -leLess than or equal to  -gtGreater than  -geGreater than or equal to  -eqEqual to  -neNot.
Programozás III KIVÉTEL.
Illés Zoltán ELTE Informatikai Kar
Haladó Programozás System.Threading.Tasks.Task OE-NIK HP.
V 1.0 OE-NIK HP 1 Haladó Programozás Folyamatok Szálkezelés alapok.
Programozás III KIVÉTEL. KIVÉTELKEZELÉS Hibátlan program nincs!!! eddig hiba esetén leállt a program. Példa ilyen hibákra: ─ ArrayBoundsOfException (tömb.
Szebb és használhatóbb programok Vezérlőelemek dinamikus felhelyezése.
Winnie the pooh & friends
TÁMOP /1-2F JAVA programozási nyelv NetBeans fejlesztőkörnyezetben I/13. évfolyam Osztályok, objektumok definiálása és alkalmazása. Saját.
Kiss Tibor System Administrator (MCP) ISA Server 2006.
Farkas Bálint | Technical Evangelist | Microsoft.
A BCD használata üzleti partnerek felkutatásához
Maven és Ant Build eszközök bemutatása
Párhuzamos programozás
C# kódolási konvenciók
“Tudásmegosztás és szervezeti problémamegoldás a mesterséges intelligencia korában” Levente Szabados Technológiai Igazgató.
Gépészeti informatika (BMEGEMIBXGI)
ResearcherID bemutatása
Farkas Bálint | Technical Evangelist | Microsoft
Haladó Programozás System.Threading.Tasks.Task OE-NIK HP.
Adatkötés Sablonokkal
Hernyák Zoltán Magasszintű Programozási Nyelvek I.
Hernyák Zoltán Programozási Nyelvek II.
A sas törénete… A bemutatót készítette: Mike
Többplatformos appfejlesztés Xamarinnal és Visual Studióval
Web programozás és haladó fejlesztési technikák – C#
„Agilis-e vagy?” – egy váltókezelő naplója
HWSW Meetup – Felhő és ami mögötte van
Microsoft SQL licenselés a gyakorlatban
JAVA programozási nyelv NetBeans fejlesztőkörnyezetben I/13. évfolyam
Thread és Task.
Folyamatok.
Szálszinkronizáció.
Szálszinkronizáció.
Függvénysablonok használata
Előadás másolata:

Web programozás és haladó fejlesztési technikák Task async-await Adatpárhuzamosság

Task

Emlékeztető A ParameterizedThreadStart delegált egy void(object) szignatúrájú metódus Szálnak bemeneti paramétert objectként kell átpasszolni a Start() metódus paraméterezésével static void Koszon(object o) { //string nev = (string)o; string nev = o.ToString(); //ebben az esetben eleg ez is Console.WriteLine("Hello " + o + "!"); } static void Main(string[] args) Thread t = new Thread(Koszon); Console.WriteLine("Szál indítása!"); t.Start("Pistike"); Console.WriteLine("Várakozás a befejezésre..."); t.Join(); Console.ReadLine();

Thread Alacsony szintű eszköz szálak definiálására Nehezen kezelhetőek az egymásra épülések Költséges létrehozni, megszüntetni, váltani közöttük Nincs beépített lehetőség „barátságos” leállításra Nincs visszatérési érték definiálására lehetőség A metódus felparaméterezése sem túl fejlesztőbarát

Task Aszinkron elvégzett „feladat” A háttérben egy ThreadPool egy eleme van: magasabb absztrakciós szinten dolgozunk Lehetőségek Visszatérési érték Nem-blokkoló egymásra épülések Kivételkezelés Leállítás

Hagyományos szál vs. Task Használjunk hagyományos szálakat, ha: A szálnak a normálistól eltérő prioritással kell futnia – a ThreadPool-on minden szál normál prioritással fut Előtérszálra van szükség – minden ThreadPool szál háttérszál A szál extrém hosszú műveletet végez (pl. az alkalmazás teljes élettartama alatt futnia kell) Abort()-ra lehet szükség Minden más esetben Task ajánlott Könnyen alkalmazható, robosztus eszköz Széleskörű alkalmazási lehetőségek (feladatmegszakítás, kivételkezelés, ütemezés, stb) A szál extrém hosszú műveletet végez (pl. az alkalmazás teljes élettartama alatt futnia kell) Ebben amúgy nem vagyok biztos, hogy még most is így van, lásd LongRunning (ilyenkor nem threadpoolra teszi). De mindenesere ilyenkor nem árt meg a nem Task szál. Abort: _azonnali_ kinyírása a szálnak, ez a tasknál nincs, csak cancel. Mellesleg threadeknél meg egyebeknél is nagyon ellenjavallt az abort. You need the thread to run with a non-normal thread priority. All thread pool threads run at normal priority. Although you can change this, it is not recommended, and the priority change does not persist across thread pool operations. ■■ You need the thread to behave as a foreground thread, thereby preventing the application from dying until the thread has completed its task. For more information, see the ”Foreground Threads vs. Background Threads” section later in this chapter. Thread pool threads are always background threads, and they may not complete their task if the CLR wants to terminate the process. ■■ The compute-bound task is extremely long-running; this way, I would not be taxing the thread pool’s logic as it tries to figure out whether to create an additional thread. ■■ You want to start a thread and possibly abort it prematurely by calling Thread’s Abort method (discussed in Chapter 22, “CLR Hosting and AppDomains”).

Task indítása Taskok indítása paraméterrel: Task task1 = new Task(new Action(PrintMessage)); Task task2 = new Task(delegate { PrintMessage(); }); Task task3 = new Task(() => PrintMessage()); Task task4 = new Task(() => { PrintMessage(); }); Taskok indítása paraméterrel: A new Task Action-t vagy Action<object>-et vár el, a Task.Run csak Action-t! new Task(LongOperation).Start(); new Task(LongOperationWithParam, 15).Start(); Task t = Task.Run(() => LongOperation()); //.NET 4.5 Task t = Task.Run(() => LongOperationWithParam(15)); //.NET 4.5 Task t = new TaskFactory().StartNew(LongOperation); Factory-s megoldásnak sok-sok overloadja van. Valamint egy factory-t felparaméterezhetünk, ahogy akarunk, és az adott paraméterekkel indíthatunk akár több darab Taskot is. (A példa nem mutatja meg ennek a kihasználását) Task.Run, new segítségével is lehet visszatérési értékkel rendelkező Taskot indítani.

Task visszatérési értékkel Taskok indítása visszatérési értékkel rendelkező művelet esetén: A Result tulajdonság megvárja a művelet végét (blokkol), ezért érdemes nem azonnal a Start után hívni (vagy lásd később) Task<int> task = new Task<int>(LongOperationWithReturnValue); task.Start(); // Func<Tresult> ! // ... más műveletek... int result = task.Result; Console.WriteLine(result);

Thread esetén közös változóba gyűjtenénk a „kimenetet” static void Main(string[] args) { int result = 0; Thread t1 = new Thread(() => { Thread.Sleep(1500); result = 42; }); t1.Start(); Console.WriteLine("Feldolgozás elindult!"); t1.Join(); Console.WriteLine("Feldolgozás vége!"); Console.WriteLine($"Eredmény: {result}"); Console.ReadLine(); } Feldolgozás elindult! Feldolgozás vége! Eredmény: 42

Task esetén adott a Result tulajdonságon keresztül static void Main(string[] args) { Task<int> t1 = new Task<int>(() => { Thread.Sleep(1500); return 42; }); t1.Start(); Console.WriteLine("Feldolgozás elindult!"); t1.Wait(); Console.WriteLine("Feldolgozás vége!"); Console.WriteLine($"Eredmény: {t1.Result}"); Console.ReadLine(); } Feldolgozás elindult! Feldolgozás vége! Eredmény: 42

Task esetén a Result lekérdezése blokkol static void Main(string[] args) { Task<int> t1 = new Task<int>(() => { Thread.Sleep(1500); return 42; }); t1.Start(); Console.WriteLine("Feldolgozás elindult!"); Console.WriteLine($"Feldolgozás vége!\nEredmény: {t1.Result}"); Console.ReadLine(); } Feldolgozás elindult! Feldolgozás vége! Eredmény: 42

Várakozás Taskra Bármilyen esetben, amikor a Task műveletére várni kell (pl. eredményt képez, tömböt feltölt, beállítást végez, fájlt ment…) Hátrány: ezek a hívások mind blokkolnak task.Wait(); //várakozás, míg kész (blokkol) Task.WaitAll(taskArray); //várakozás, míg mind kész (blokkol) Task.WaitAny(taskArray); //várakozás, míg legalább az egyik kész (blokkol) //vagy Task.WaitAll(task1, task2, task3); //mint fent Task.WaitAny(task1, task2, task3); //mint fent

Több Task együttes bevárása List<Task> ts = new List<Task>() { new Task(() => { Thread.Sleep(800); Console.WriteLine("Kész vagyok!"); }), new Task(() => { Thread.Sleep(1200); Console.WriteLine("Kész!"); }), new Task(() => { Thread.Sleep(1000); Console.WriteLine("Elkészült!"); }), new Task(() => { Thread.Sleep(1100); Console.WriteLine("Ready!"); }), }; foreach (Task t in ts) t.Start(); Task.WaitAll(ts.ToArray()); Console.WriteLine("Minden feladat végrehajtva!"); Kész vagyok! Elkészült! Ready! Kész! Minden feladat végrehajtva!

Continuation-ök Az eredeti Task lefutása után egy új Task indul majd a megadott művelettel (a t az előző, befejeződött Taskra való referencia) Feltételes indítás: Task<int> continuedTask = new Task<int>(LongOperationWithReturnValue); //nem blokkol, mint a Wait: continuedTask.ContinueWith(t => Console.WriteLine("The result was: " + t.Result)); //csak ha hiba nélkül futott az eredeti Task: continuedTask.ContinueWith(t => Console.WriteLine("The result was: " + t.Result), TaskContinuationOptions.OnlyOnRanToCompletion); //csak ha cancelezték az eredeti Taskot: continuedTask.ContinueWith(t => Console.WriteLine("The task was canceled!"), TaskContinuationOptions.OnlyOnCanceled); //csak ha hibára futott az eredeti Task: continuedTask.ContinueWith(t => Console.WriteLine("The task threw " + "an exception: " + t.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted);

Task folytatása Task t = new Task(() => { Thread.Sleep(1000); Console.WriteLine("Kész!"); }); t.ContinueWith(x => { Console.WriteLine($"Task #{x.Id} véget ért!"); }); t.Start(); Console.WriteLine("Task elindítva!"); Task elindítva! Kész! Task #2 véget ért!

Több Task együttes folytatása List<Task> ts = new List<Task>() { new Task(() => { Thread.Sleep(800); Console.WriteLine("Kész vagyok!"); }), new Task(() => { Thread.Sleep(1200); Console.WriteLine("Kész!"); }), new Task(() => { Thread.Sleep(1000); Console.WriteLine("Elkészült!"); }), new Task(() => { Thread.Sleep(1100); Console.WriteLine("Ready!"); }), }; Task.WhenAll(ts.ToArray()).ContinueWith(x => { Console.WriteLine("Minden feladat végrehajtva!"); }); foreach (Task t in ts) t.Start(); Console.ReadLine(); Kész vagyok! Elkészült! Ready! Kész! Minden feladat végrehajtva!

Eredménnyel rendelkező Taskok együttes folytatása List<Task<int>> ts = new List<Task<int>>() { new Task<int>(() => { Thread.Sleep(800); return 800; }), new Task<int>(() => { Thread.Sleep(600); return 600; }), new Task<int>(() => { Thread.Sleep(1200); return 1200; }), new Task<int>(() => { Thread.Sleep(1100); return 1100; }), }; Task.WhenAll(ts.ToArray()).ContinueWith(x => { //x.Result: int[] Console.WriteLine("Vége! Az eredmények összege: " + x.Result.Sum()); }); foreach (var t in ts) t.Start(); Console.ReadLine(); Vége! Az eredmények összege: 3700

Task elindult Baj történt, az alábbi üzenettel: One or more errors occurred. Hibakezelés a Taskban Ha egy Taskban hiba történik, az Exception lenyelődik, és a Wait() vagy Result hívásakor dobódik el egy gyűjteményes Exception (AggregateException) formájában Task t = new Task(() => { Thread.Sleep(500); throw new Exception("houston, baj van!"); Console.WriteLine("Ez sosem íródik ki."); }); t.Start(); Console.WriteLine("Task elindult"); try { t.Wait(); } catch (Exception e) { Console.WriteLine("Baj történt, az alábbi üzenettel: " + e.Message); }

Hibakezelés a Taskban Ha egy Taskban hiba történik, az Exception lenyelődik, és a Wait() vagy Result hívásakor dobódik el egy gyűjteményes Exception (AggregateException) formájában Task t = new Task(() => { Thread.Sleep(500); throw new Exception("houston, baj van!"); Console.WriteLine("Ez sosem íródik ki."); }); t.Start(); Console.WriteLine("Task elindult"); try { t.Wait(); } catch (AggregateException e) { foreach (var ie in e.InnerExceptions) Console.WriteLine("Baj történt, az alábbi üzenettel: " + ie.Message); }

Task elindult Baj történt, az alábbi üzenettel: houston, baj van! Hibakezelés a Taskban Ha egy Taskban hiba történik, az Exception lenyelődik, és a Wait() vagy Result hívásakor dobódik el egy gyűjteményes Exception (AggregateException) formájában Task t = new Task(() => { Thread.Sleep(500); throw new Exception("houston, baj van!"); Console.WriteLine("Ez sosem íródik ki."); }); t.Start(); Console.WriteLine("Task elindult"); try { t.Wait(); } catch (AggregateException e) { Console.WriteLine("Baj történt, az alábbi üzenettel: " + string.Join("\n", e.InnerExceptions.Select(x => x.Message))); }

AggregateException Task t = new Task(() => { new Task(() => { throw new Exception("asd"); }, TaskCreationOptions.AttachedToParent).Start(); Thread.Sleep(500); throw new Exception("houston, baj van!"); Console.WriteLine("Ez sosem íródik ki."); }); t.Start(); Console.WriteLine("Task elindult");

AggregateException try { t.Wait(); } catch (AggregateException e) { e.Handle(ie => { if (ie.Message.Contains("houston")) Console.WriteLine("ezt ismerjük, kezeljük"); return true; } Console.WriteLine("Baj történt, az alábbi üzenettel: " + ie.Message); return false; }); Task elindult ezt ismerjük, kezeljük Baj történt, az alábbi üzenettel: One or more errors occurred. Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> System.Exception: asd at xx_Eloadashoz.Program.<>c.<Main>b__0_1() in ... Press any key to continue . . .

Hibakezelés Continuationnel Task t = new Task(() => { new Task(() => { throw new Exception("asd"); }, TaskCreationOptions.AttachedToParent).Start(); Thread.Sleep(500); throw new Exception("houston, baj van!"); Console.WriteLine("Ez sosem íródik ki."); }); t.ContinueWith(x => { Console.WriteLine("Hiba volt: " + x.Exception.Message); }, TaskContinuationOptions.OnlyOnFaulted); t.Start(); Console.WriteLine("Task elindult"); Task elindult Hiba volt: One or more errors occurred.

Task leállítása A Task-ban végzett műveletben kell kezelni a leállítás lehetőségét Szinkronizált CancellationTokenen keresztül történik a Task értesítése, így megoldva a közös változó használatának problémáját Használható ellenőrzési módok: cancellationToken.IsCancellationRequested: bool tulajdonság. Ha igaz, ki kell lépni a függvényből cancellationToken.ThrowIfCancellationRequested(): Exception keletkezik, ha leállítás volt kérelmezve (ezzel kilép a függvényből) Előny: az Exception egyértelműen mutatja, hogy a leállás nem a művelet vége miatt történt The Microsoft .NET Framework offers a standard pattern for canceling operations. This pattern is cooperative, meaning that the operation that you want to cancel has to explicitly support being canceled.

Task leállítása CancellationTokenSource cts = new CancellationTokenSource(); Task t = new Task(() => { for (int i = 0; i < 1000; i++) { Thread.Sleep(10); Console.Write(i + "\t"); if (cts.Token.IsCancellationRequested) return; } }, cts.Token); t.Start(); Console.WriteLine("Task elindult!"); Thread.Sleep(1200); Console.WriteLine("Leállítás kezdeményezése..."); cts.Cancel(); Task elindult! 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 Leállítás kezdeményezése... 54

Task leállítása - kivétel CancellationTokenSource cts = new CancellationTokenSource(); Task t = new Task(() => { for (int i = 0; i < 1000; i++) { Thread.Sleep(10); Console.Write(i + "\t"); cts.Token.ThrowIfCancellationRequested(); } }, cts.Token); t.Start(); Console.WriteLine("Task elindult!"); Thread.Sleep(1200); Console.WriteLine("Leállítás kezdeményezése..."); cts.Cancel();

Task leállítása try { t.Wait(); } catch (AggregateException e) { e.Handle(ie => { if (ie is OperationCanceledException) Console.WriteLine("Leállítva!"); return ie is OperationCanceledException; }); } Task elindult! 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 Leállítás kezdeményezése... 54 Leállítva!

Task leállítása - continuation CancellationTokenSource cts = new CancellationTokenSource(); Task t = new Task(() => { for (int i = 0; i < 1000; i++) { Thread.Sleep(10); Console.Write(i + "\t"); cts.Token.ThrowIfCancellationRequested(); } }, cts.Token); t.ContinueWith(x => { Console.WriteLine("Leállítva!"); }, TaskContinuationOptions.OnlyOnCanceled); t.Start(); Console.WriteLine("Task elindult!"); Thread.Sleep(600); Console.WriteLine("Leállítás kezdeményezése..."); cts.Cancel();

GUI-elem kezelése Windows-os grafikusfelület-elemekhez általában nem lehet hozzányúlni, csak a létrehozó szálról (GUI szál) Még közvetve sem WPF, Windows Forms is! Van kevés kivétel (bizonyos függvények, adatkötésnél a PropertyChanged) Általános megoldás: Invoke Függvény végrehajtatása a GUI szállal Dispatcher.Invoke(() => { label.Content = ...; listBox.Items.Add(...); });

GUI-elem kezelése Rövidebb módszer, ha a Task eredményét kiíró műveletet is külön Taskként indítjuk, megadott taskütemező (TaskScheduler) segítségével Beépített taskütemezők: Thread Pool Task Scheduler: a ThreadPool-on indítja a taskokat (alapértelmezett) Synchronization Context Task Scheduler: a felhasználói felület szálján indítja a taskokat – ezzel kell indítani, ha GUI-elemet akarunk kezelni Referencia „megszerzése”: a GUI szálján TaskScheduler.FromCurrentSynchronizationContext() Task<int> taskWithReturnValue = Task.Run(() => { Thread.Sleep(1000); return 6; }); taskWithReturnValue.ContinueWith( t => textBox1.Text = "Result: " + t.Result, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.FromCurrentSynchronizationContext()); The task infrastructure is very flexible, and TaskScheduler objects are a big part of this flexibility. A TaskScheduler object is responsible for executing scheduled tasks and also exposes task information to the Visual Studio debugger. The FCL ships with two TaskScheduler-derived types: the thread pool task scheduler and a synchronization context task scheduler. By default, all applications use the thread pool task scheduler. This task scheduler schedules tasks to the thread pool’s worker threads and is discussed in more detail in this chapter’s “How the Thread Pool Manages Its Threads” section. You can get a reference to the default task scheduler by querying TaskScheduler’s static Default property. The synchronization context task scheduler is typically used for applications sporting a graphical user interface, such as Windows Forms, Windows Presentation Foundation (WPF), Silverlight, and Windows Store applications. This task scheduler schedules all tasks onto the application’s GUI thread so that all the task code can successfully update UI components like buttons, menu items, and so on. The synchronization context task scheduler does not use the thread pool at all. You can get a reference to a synchronization context task scheduler by querying TaskScheduler’s static FromCurrentSynchronizationContext method. You can, of course, define your own class derived from TaskScheduler if you have special task scheduling needs. Microsoft has provided a bunch of sample code for tasks and includes the source code for a bunch of task schedulers in the Parallel Extensions Extras package, which can be downloaded from here: http://code.msdn.microsoft.com/ParExtSamples. Here are some of the task schedulers included in this package: ■■ IOTaskScheduler This task scheduler queues tasks to the thread pool’s I/O threads instead of its worker threads. ■■ LimitedConcurrencyLevelTaskScheduler This task scheduler allows no more than n (a constructor parameter) tasks to execute simultaneously. OrderedTaskScheduler This task scheduler allows only one task to execute at a time. This class is derived from LimitedConcurrencyLevelTaskScheduler and just passes 1 for n. ■■ PrioritizingTaskScheduler This task scheduler queues tasks to the CLR’s thread pool. After this has occurred, you can call Prioritize to indicate that a Task should be processed before all normal tasks (if it hasn’t been processed already). You can call Deprioritize to make a Task be processed after all normal tasks. ■■ ThreadPerTaskScheduler This task scheduler creates and starts a separate thread for each task; it does not use the thread pool at all.

async-await

Aszinkronitás „Asynchrony is essential for activities that are potentially blocking (…). Access to a web resource sometimes is slow or delayed. If such an activity is blocked within a synchronous process, the entire application must wait. In an asynchronous process, the application can continue with other work that doesn't depend on the web resource until the potentially blocking task finishes.” JavaScript Az aszinkron kódolásra kiváló eszköz a JavaScript nyelv használata: az alapból aszinkron felépítésű kódban minden hosszadalmas függvényhívás, ahol erőforrásra kell várakozni, átlépésre kerül. Amikor a folyamat végzett, a visszatérésével egy úgynevezett callback-function foglalkozik.

Szinkron példa Console.WriteLine("Megkezdem a letöltést..."); string tartalom = new WebClient().DownloadString("http://users.nik.uni-obuda.hu/prog3/_data/war_of_westeros.xml"); Console.WriteLine("Letöltve!"); Console.WriteLine(tartalom.Contains("Lannister") ? "Van benne Lannister" : "Nincs benne Lannister"); Megkezdem a letöltést... Letöltve! Van benne Lannister

Klasszikus aszinkron megoldás esemény alapon static void Main(string[] args) { Console.WriteLine("Megkezdem a letöltést..."); WebClient wc = new WebClient(); wc.DownloadStringCompleted += Wc_DownloadStringCompleted; wc.DownloadStringAsync(new Uri("http://users.nik.uni-obuda.hu/prog3/_data/war_of_westeros.xml")); Console.ReadLine(); } private static void Wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) Console.WriteLine("Letöltve!"); Console.WriteLine(e.Result.Contains("Lannister") ? "Van benne Lannister" : "Nincs benne Lannister");

Task alapú megoldás Console.WriteLine("Megkezdem a letöltést..."); Task<string> t = new WebClient().DownloadStringTaskAsync("http://users.nik.uni-obuda.hu/prog3/_data/war_of_westeros.xml"); t.ContinueWith(x => { Console.WriteLine("Letöltve!"); Console.WriteLine(x.Result.Contains("Lannister") ? "Van benne Lannister" : "Nincs benne Lannister"); });

async-await async Task<string> AszinkronValasz() { await Task.Delay(2000); return "kész"; } await „bevárás” A végrehajtás szüneteltetése, amíg a „bevárt” Task nem végez awaitelni Task-ot lehet, akár visszatérési értékkel Sok beépített nyelvi elem (GetXXXAsync()) async Ahol awaitelsz valamit, azt a metódust az async kulcsszóval meg kell jelölni Csak void, Task és Task <TResult> visszatérésű metódusok lehetnek async-ek

async-await alapú megoldás static async void Elemez(string url) { Console.WriteLine("Letöltés megkezdve!"); string tartalom = await new WebClient().DownloadStringTaskAsync(url); Console.WriteLine("Letöltve!"); Console.WriteLine(url + ": " + (tartalom.Contains("Lannister") ? "van benne Lannister" : "nincs benne Lannister")); }

async-await alapú megoldás static void Main(string[] args) { Console.WriteLine("Megkezdem a letöltéseket..."); string urls = "http://users.nik.uni-obuda.hu/prog3/_data/war_of_westeros.xml, http://users.nik.uni-obuda.hu/prog3, http://nik.uni-obuda.hu/, http://uni-obuda.hu"; foreach (var url in urls.Split(',').Select(x => x.Trim())) Elemez(url); Console.WriteLine(url + " elemzése elindult"); } Console.ReadLine(); static async void Elemez(string url) {…} Megkezdem a letöltéseket... Letöltés megkezdve! http://users.nik.uni-obuda.hu/prog3/_data/war_of_westeros.xml elemzése elindult http://users.nik.uni-obuda.hu/prog3 elemzése elindult http://nik.uni-obuda.hu/ elemzése elindult http://uni-obuda.hu elemzése elindult Letöltve! http://users.nik.uni-obuda.hu/prog3/_data/war_of_westeros.xml: van benne Lannister http://users.nik.uni-obuda.hu/prog3: nincs benne Lannister http://uni-obuda.hu: nincs benne Lannister http://nik.uni-obuda.hu/: nincs benne Lannister

async-await a Main()-ben static async Task Main(string[] args) { Console.WriteLine("Megkezdem a letöltést..."); string tartalom = await new WebClient().DownloadStringTaskAsync("http://users.nik.uni-obuda.hu/prog3/_data/war_of_westeros.xml"); Console.WriteLine("Letöltve!"); Console.WriteLine(tartalom.Contains("Lannister") ? "Van benne Lannister" : "Nincs benne Lannister"); Console.ReadLine(); } C#7 óta lehet ilyet

Vizuális alkalmazásoknál látványos async Task<string> AszinkronValasz() { await Task.Delay(2000); return "kész"; } private async void button_Click(object sender, RoutedEventArgs e) textBox.Text = await AszinkronValasz();

Párhuzamos? Valójában önmagában nincs külön szál Az async módosítószóval megjelölt metódus az await kulcsszóval megjelölt hívásig szinkron kerül végrehajtásra Ott azonban a metódus „suspended” állapotú lesz, amíg a Task nem végez A Task persze „dönthet úgy” hogy külön szálat alkalmaz Amíg a metódus áll, a vezérlés visszatér a hívás helyére, és továbblép Amikor a Task végzett, a vezérlés visszakerül oda

Adatpárhuzamos megoldások

Parallel class Parallel.For(int, int, Action<>) Parallel.ForEach(IEnumerable<>, Action<>) Parallel.Invoke(Action[])

Parallel.For Gyakorlatilag a for ciklus magjának kifejtése és Action<int> delegált meghívása minden ciklusváltozóra int[] eredm = new int[10]; Parallel.For(0, eredm.Length, i => { eredm[i] = i * i; Console.Write(i + " kész! "); } ); Console.WriteLine(); for (int i = 0; i < eredm.Length; i++) Console.Write(i + ": " + eredm[i] + ", "); vigyázni, ha összefüggés van az adatok között: versenyhelyzet! 0 kész! 1 kész! 3 kész! 4 kész! 5 kész! 6 kész! 7 kész! 8 kész! 9 kész! 2 kész! 0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81,

Parallel.ForEach Hasonlóan a Parallel.For()-hoz, a gyűjtemény típusának megfelelő Action<T> delegáltat alkalmaz Parallel.ForEach("hello world!", e => { Console.Write(char.ToUpper(e)); }); Console.ReadLine(); OHELWRD!LO L

Parallel.Invoke A Parallel.Invoke() egy Action[] bemenetet kap paraméterként, amely delegáltakat párhuzamosan igyekszik végrehajtani Az utasítás blokkol, addig nem lép tovább amíg minden Action végrehajtása véget nem ért Parallel.Invoke( BasicAction, // Param #0 - static method () => // Param #1 - lambda expression { Console.WriteLine("Method=beta,Thread={0}", Thread.CurrentThread.ManagedThreadId); }, delegate () // Param #2 - in-line delegate Console.WriteLine("Method=gamma,Thread={0}", Thread.CurrentThread.ManagedThreadId); } );

Források Szabó-Resch Miklós Zsolt és Cseri Orsolya Eszter Haladó Programozás előadásfóliái Kertész Gábor Párhuzamos és Elosztott Rendszerek Programozása előadásfóliái MSDN