TPL – konkurenční, paralelní a asynchronní kód pro náročné René Stein
TPL základy – co byste měli znát Třída Task. „Thread je mrtev, ať žije Task“? Spuštění tásku a základní operace pro skládání tásků (WaitAny, WaitAll). Kooperativní stornování tásku. Co je synchronizační kontext a proč máme metodu ConfigureAwait. Klíčová slov async a await v C#.
TPL základy – co byste měli znát II Asynchronní != paralelní. (a asynchronní nebo paralelní != zázrak) Proč bychom neměli používat async void metody. Jaký je životní cyklus objektu tásku? (Toto by neměl být váš životní cyklus) „Přišel jsem, viděl jsem, bohatě stačilo a (nejpozději po svačině) rád odcházím“
Životní cyklus tásku Zdroj:
Něco jednoduchého – problémy s TaskCompletionSource „Co jednou Task spojil, toTaskCompletionSource musí rozdělit“ Věčnost?
TaskCompletionSource TaskCompletionSource = Promise. Task = Future. I při kódování by se sliby měly plnit. I když to občas znamená, že ten druhý si bude přát, abyste mu nikdy nic neslíbili, protože může od vás čekat je krev, pot, slzy, deadlock, a když jste v dobrém rozmaru, tak výjimku BTW:Jsou sliby oboustranné?
Rstein.Async – DebugTaskCompletionSource DebugTaskCompletionSourceServices. DetectBrokenTaskCompletionSources(); (Detekce nesplněných slibů bez záruky - jde jen o preview verzi) Idioti jsou jako láska - slibují víc, než mohou splnit. (G. Laub) Na TaskCompletionSource bych v této souvislosti nezapomínal! (Dodatek: René Stein) Každý slib je na nejlepší cestě k tomu být falešný. (J.P. Sartre)
Scheduler a ThreadPool TPL scheduler.Net ThreadPool TPL scheduler se má k.Net ThreadPoolu jako ?
Co s hříšnými touhami po jiném Scheduleru? Potřebujeme jiné schedulery než ty, které jsou v.Net Frameworku? –„ThreadPoolScheduler“ - Default –„SynchronizationContextScheduler“ FromCurrentSynchronizationContext() –ConcurrentExclusiveSchedulerPair (náhrada za „lock“, ReaderWriterLock) !!! Většinou ne !!! - ale když už ano
„Extra“ schedulery v PEE Další slušnou sbírku schedulerů naleznete v Parallel Extensions Extras
Vlastní scheduler Nejjednodušší je podle mě: CurrentThreadScheduler (A v téhle jednoduchosti fakt nehledejte žádnou krásu)
Vlastní scheduler – problémy a řešení (Otravný) FallbackScheduler, který může použít CurrentThreadSche duler jako záložní scheduler
Rstein.Async – dvojice IProxyScheduler a ITaskScheduler Integrace s TPL – „obyčejný“ TaskScheduler
Rstein.Async – ProxyScheduler a TaskSchedulerBase
FallbackScheduler s pořadovým číslem 2 je sice stále nudný, ale už jej alespoň dokážeme napsat a používat bez vyvolání výjimky. FALLBACKSCHEDULER II
Rstein.Async a IoServiceScheduler Scheduler, který nevyřídí žádný tásk do té doby, dokud mu nepropůjčíte vlákno zavoláním jedné z jeho metod Poll, PollOne, Run, RunOne Boost.Asio.Net
Rstein.Async - IoServiceSynchronizationContext
Rstein.Async a IoServiceThreadPoolScheduler „Autonomní“ scheduler. (Velmi) jednoduchý threadpool. Používá IoServiceScheduler.
Nelehký životní cyklus SimpleUploaderu Jak by řekla nejen programátorka Maruška – funkčnost a čitelnost kódu nad zlato i rychlost. V praxi se nejčastěji setkáte s kódem, který je: –Občas nefunkční, ale nikdo neví „proč“. –Nečitelný, ale všichni vám zdůvodní „proč“. –Po čase pomalý a plný (dead)locků, které jsou zpestřením nudného vývojářského života. Proč?
Aktor model Zjednodušeně – aktor je objekt (prozatím nekamenovat!), u kterého platí, že v jednom okamžiku zpracovává maximálně jednu zprávu („provádí jednu metodu“). A to bez ohledu na počet požadavků z různých vláken. Všechny požadavky na aktora jsou aktorem zpracovány sekvenčně!
Aktor jako objekt z lepší společnosti Objekty, u kterých se při volání metody může změnit jejich interní stav (a přitom se zbavíme „locků“) Aktor je (prý) lepší objekt než “klasické“ objekty (nejen) z C- like jazyků.
Charakteristika konvenčního aktor modelu Aktor při zpracování zprávy („po obdržení požadavku“) může: –Poslat zprávy (požadavky) dalším aktorům. –Změnit svůj stav. A připravit se tak na příjem další zprávy (požadavku). –Vytvořit další aktory pro zpracování nových zpráv (požadavků).
Aktoři a thready Jak zabít aktory i s aplikaci? Frontu požadavků každého aktora obsluhuje právě jeden thread. Tento thread je v exkluzivním vlastnictví aktora. Co je „threadless“ actor model?
Rstein.Async - StrandSchedulerDecorator STRAND = v jednom okamžiku běží maximálně jeden tásk Implicitní strand = m_originalScheduler.Maxim umConcurrencyLevel = 1 StrandSchedulerDecorator ITaskScheduler (nejčastěji IoServiceThreadPoolScheduler)
Rstein.Async - podpora pro aktory Použita dynamická proxy Castle.DynamicProxy var uploaderActorProxy = proxyEngine.CreateProxy (simpleUploaderActor ); ProxyGenerationHook „Jaké metody budeme odchytávat v interceptorech“ ActorMethodInterceptor „metody budou zpracovány sekvenčně – každý aktor má svůj StrandScheduler“ PreventArgumentBaseTypeLeakInterceptor „Aktor nevydá svou pravou podstatu z žádné metody, ale vždy si navlékne proxy masku“
Tradiční ukázky aktorů I Ping Pong (Tomáš Aquinský proti Sigeru Brabantskému)
Tradiční ukázky aktorů II (Problematický) Ping Pong s čekáním na odpověď Podle mě je takzvaný „ASK“ vzor pro většinu scénářů antivzor. „Don‘t ASK“ Actor by měl komunikovat s ostatními aktory stylem „Fire & Forget”. –Budeme čekat na odpověď a blokovat zpracování dalších zpráv? –Zpracujeme jinou zprávu? (co vnitřní stav aktora?)
Schéma komunikace mezi aktory - ukázka III ILibraryActor IBookLinesParser Actor IBookLineConsumerActor n (CountWordsInLineActor) ICountWordAggregate Actor IBookLineConsumerActor 1 (CountWordsInLineActor) IResultProcessorActor (PrintTopWordsProces sorActor)
Co naši aktoři prozatím nepodporují O „pravém“ actor modelu (Erlang, Elixir…) se dá mluvit teprve tehdy: –Jsme-li schopni aktory od sebe dokonale izolovat. –Jsme-li schopni aktory aktivovat v jiném procesu/na jiném počítači (distribuovaní aktoři). Ošetření chyb např. elegantním a vývojáři milovaným stylem „Let it crash“. Přesto – i „naši“ zjednodušení aktoři jsou pro mnoho aplikací požehnáním
Alternativní knihovny pro psaní aktorů TPL Dataflow – např. pomocí ActionBlocku s konkurencí rovnou jedné. ActorFX F# Zdroj:
AKKA.NET Zdroj:
Tradiční problémy s aktory Jestliže aktoři mohou modifikovat stav „zpráv“ (argumentů metod), máte „race condition“. Zprávy-argumenty musí být imutabilní. Ani použití aktorů neznamená jistotu, že se v aplikaci neobjeví deadlock. Jeden aktor se může snadno stát brzdou pro ostatních aktory. Výkonnostní problémy.
Alternativní konkurenční modely TPL Dataflow Reactive Extensions – RX framework Software transactional memory Communicating Sequential Processes (CSP) a mnoho dalších
Zdroje – malý výběr Knihovna Rstein.Async. Seriál na blogu o knihovně (prozatím 5 dílů)
Answer? answer = await Task.Run(()=> ); Dotazy
René Stein Vývoj aplikací, veřejné a inhouse kurzy