Parallel FX a paralelní programování na platformě. ET

Podobné dokumenty
Aleš Keprt Univerzita Palackého v Olomouci listopad 2008, listopad 2009 PARALLEL FX A PARALELNÍ PROGRAMOVÁNÍ NA PLATFORMĚ.NET 4.0

Paralelní a asynchronní programování. Zdeněk Jurka

Jakub Čermák Microsoft Student Partner

Procesy a vlákna (Processes and Threads)

Paralelní programování

Obsah. Kapitola 1 Hardware, procesory a vlákna Prohlídka útrob počítače...20 Motivace pro vícejádrové procesory...21

Procesy a vlákna - synchronizace

Asynchronní programování v.net

Základní datové struktury

Paralelní programování

Reaktivní programování v.net

Paralení programování pro vícejádrové stroje s použitím OpenMP. B4B36PDV Paralelní a distribuované výpočty

Paralelní programování

Řada programovacích jazyků nabízí prostředky pro řešení meziprocesové komunikace jako je synchronizace a řízení přístupu do kritické sekce.

Pavel Procházka. 3. prosince 2014

Paralelní programování

Management procesu I Mgr. Josef Horálek

OPS Paralelní systémy, seznam pojmů, klasifikace

Paralelní programování

Bridge. Známý jako. Účel. Použitelnost. Handle/Body

Seznámení s prostředím dot.net Framework

8 Třídy, objekty, metody, předávání argumentů metod

Principy operačních systémů. Lekce 5: Multiprogramming a multitasking, vlákna

Principy operačních systémů. Lekce 6: Synchronizace procesů

Lineární datové struktury

Spuštění instalace. nastavení boot z cd v BIOSu vložení CD s instal. médiem spuštění PC. nastavení parametrů instalace (F2 čěština)

Vlákna a přístup ke sdílené paměti. B4B36PDV Paralelní a distribuované výpočty

Z. Kotala, P. Toman: Java ( Obsah )

Ovladače pro Windows. Ovladače Windows A4M38KRP. Str. 1

IRAE 07/08 Přednáška č. 7. Začátek (head)

Architektura rodiny operačních systémů Windows NT Mgr. Josef Horálek

Služba ve Windows. Služba (service) je program

Architektura a koncepce OS OS a HW (archos_hw) Architektura a koncepce OS Jádro OS (archos_kernel) Architektura a koncepce OS Typy OS (archos_typy)

Programování v C++ 2, 4. cvičení

PARADIGMATA PROGRAMOVÁNÍ 2 PŘÍSLIBY A LÍNÉ VYHODNOCOVÁNÍ

Vlákno (anglicky: thread) v informatice označuje vlákno výpočtu neboli samostatný výpočetní tok, tedy posloupnost po sobě jdoucích operací.

Kolekce, cyklus foreach

Paralelní programování

Využití OOP v praxi -- Knihovna PHP -- Interval.cz

MATURITNÍ OTÁZKY ELEKTROTECHNIKA - POČÍTAČOVÉ SYSTÉMY 2003/2004 PROGRAMOVÉ VYBAVENÍ POČÍTAČŮ

Přednáška. Vstup/Výstup. Katedra počítačových systémů FIT, České vysoké učení technické v Praze Jan Trdlička, 2012

Tento studijní blok má za cíl pokračovat v základních prvcích jazyka Java. Konkrétně bude věnována pozornost rozhraním a výjimkám.

ČÁST 1. Základy 32bitového programování ve Windows

Přidělování paměti II Mgr. Josef Horálek

boolean hasnext() Object next() void remove() Kolekce

ČESKÉ VYSOKÉ UČENÍ TECHNIKÉ Fakulta elektrotechnická. Microsoft Sharepoint 2007 Workflows Průmyslové informační systémy

1 - Úvod do platformy.net. IW5 - Programování v.net a C#

TŘÍDY POKRAČOVÁNÍ. Události pokračování. Příklad. public delegate void ZmenaSouradnicEventHandler (object sender, EventArgs e);

Cvičení č. 3. Sdílené prostředky a synchronizace Program Banka. 4 body

Datové struktury. alg12 1

Jako pomůcka jsou v pravém dolním rohu vypsány binární kódy čísel od 0 do 15 a binární kódy příkazů, které máme dispozici (obr.21). Obr.

Konstruktory a destruktory

Univerzita Palackého v Olomouci Radek Janoštík (Univerzita Palackého v Olomouci) Základy programování 4 - C# 3.4.

ZOS 9. cvičení, ukázky kódu. Pavel Bžoch

PROGRAMOVÁNÍ PRO MS WINDOWS 1

Maturitní témata. IKT, školní rok 2017/18. 1 Struktura osobního počítače. 2 Operační systém. 3 Uživatelský software.

Metody připojování periferií

Přijímací zkouška - informatika

Matematika v programovacích

3. Je defenzivní programování technikou skrývání implementace? Vyberte jednu z nabízených možností: Pravda Nepravda

Pokročilé architektury počítačů

4. lekce Přístup k databázi z vyššího programovacího jazyka

Procesy a vlákna Mgr. Josef Horálek

2) Napište algoritmus pro vložení položky na konec dvousměrného seznamu. 3) Napište algoritmus pro vyhledání položky v binárním stromu.

Michal Krátký. Úvod do programovacích jazyků (Java), 2006/2007

6. blok část B Vnořené dotazy

Obsah přednášky 7. Základy programování (IZAPR) Přednáška 7. Parametry metod. Parametry, argumenty. Parametry metod.

Implementace systémů HIPS: historie a současnost. Martin Dráb

Činnost počítače po zapnutí

Úvod Přetěžování Generika Kolekce Konec. Programování v C# Další jazykové konstrukce. Petr Vaněček 1 / 31

VÝUKOVÝ MATERIÁL. 3. ročník učebního oboru Elektrikář Přílohy. bez příloh. Identifikační údaje školy

Operační systémy. Jednoduché stránkování. Virtuální paměť. Příklad: jednoduché stránkování. Virtuální paměť se stránkování. Memory Management Unit

PŘETĚŽOVÁNÍ OPERÁTORŮ

State. Známý jako. Účel. Použitelnost. Stav, Object for States. umožňuje objektu měnit svoje chování v závislosti na stavu objekt mění svou třídu

Návrhové vzory. Jakub Klemsa, Jan Legerský. 30. října Objektově orientované programování.

Softwarové komponenty a Internet

Rozklad na prvočinitele. 3. prosince 2010

Ukázka zkouškové písemka OSY

Zápis programu v jazyce C#

C++ 0x aka C++11. Základním kamenem je třída std::thread

Programování II. Třídy a objekty (objektová orientovanost) 2018/19

Předmluva k aktuálnímu vydání Úvod k prvnímu vydání z roku Typografické a syntaktické konvence... 20

Seznamy a iterátory. Kolekce obecně. Rozhraní kolekce. Procházení kolekcí

Programovací jazyky. imperativní (procedurální) neimperativní (neprocedurální) assembler (jazyk symbolických instrukcí)

Základy informatiky. 2. Přednáška HW. Lenka Carr Motyčková. February 22, 2011 Základy informatiky 2

Vlákna Co je to vlákno?

Programování v jazyku C# II. 5.kapitola

Práce v textovém editoru

09. Memory management. ZOS 2006, L.Pešička

Jazyk C# (seminář 6)

KAPITOLA 1 - ZÁKLADNÍ POJMY INFORMAČNÍCH A KOMUNIKAČNÍCH TECHNOLOGIÍ

Soubor jako posloupnost bytů

1. Programování proti rozhraní

VÝUKOVÝ MATERIÁL. Bratislavská 2166, Varnsdorf, IČO: tel Číslo projektu

PB161 Programování v jazyce C++ Přednáška 7

Generické programování

TÉMATICKÝ OKRUH Softwarové inženýrství

MS WINDOWS II. Jádro. Správa objektů. Správa procesů. Zabezpečení. Správa paměti

Transkript:

Parallel FX a paralelní programování na platformě. ET Aleš Keprt Katedra informatiky, Přírodovědecká fakulta, Univerzita Palackého Tomkova 40, 779 00 Olomouc Ales.Keprt@upol.cz Abstrakt. Knihovna Parallel FX je oficiálním rozšířením platformy.net zaměřené na paralelní programování využívající vláken a sdílené paměti. Rozšiřuje tak možnosti paralelního programování v tomto objektově orientovaném prostředí o nové prvky na vyšší úrovni abstrakce. Příspěvek stručně představuje možnosti Parallel FX a snaží se je zasadit do kontextu klasických nástrojů paralelního programování s vlákny v prostředí Windows a.net. Paralelní programování je aktuálním tématem zejména díky rozmachu vícejádrových procesorů na běžných počítačích, tento trend bude navíc zcela jistě dále pokračovat. Vícejádrové procesory se však v praxi používají málo, ve výuce se velmi upřednostňují čistě sekvenční/imperativní modely programování a algoritmizace, stejně tak v praxi vidíme, že paralelizmus je stále omezen na jediný nástroj: rozdělení programu na větší celky a práci s vlákny. Parallel FX je nový framework od Microsoftu, který nabízí několik způsobů paralelizace programů. Jde o metody teoreticky známé již z minulosti, v praxi však nebyly nikdy v takové míře nasazeny - Parallel FX je rozšířením platformy.net, takže největší tíha paralelního programování se zde (konečně) přenáší z aplikací na systém. Příspěvek představí technologii Parallel FX a její výpočetní modely. Dále bude diskutovat, nakolik bude toto teoreticky zdařilé dílko Microsoftu také užitečné běžným programátorům v jejich praxi. Klíčová slova: Parallel FX, PLINQ, deklarativní/imperativní paralelizmus 1 Úvod Paralelní programování není tématem novým, v posledních letech je však tématem stále více a více důležitým. Důvodem je především aktuální trend vývoje jednotek CPU, kde vše směřuje k nasazování více a více jader do serverových i běžných stolních počítačů či notebooků. O něco pozadu za vývojem hardwaru je situace na poli softwaru většina programů se vůbec nepokouší výkon vícejádrových procesorů využívat a ty, které jsou světlými výjimkami, jsou výsledkem složité práce programátorů s vlákny, protože metody a technologie pro pohodlné paralelní programování jsou zatím stále jen v oblasti vědeckých pokusů, alternativních programovacích jazyků či výukových nástrojů. Pozitivní změnu současné situace by mohla přinést nová knihovna pro paralelní programování Parallel FX v prostředí.net, kterou vyvíjí a uvolnila k testování společnost Microsoft. Tento příspěvek představuje hlavní rysy knihovny Parallel FX v současné verzi CTP June 2008 a umisťuje ji do kontextu dosavadních nástrojů pro paralelní

programování na platformě.net a ve Windows. Všechny příklady jsou uváděny v jazyce C# a byly odzkoušeny na čtyřjádrovém procesoru Intel Core 2 Quad. 2 Klasické nástroje paralelního programování v. ETu.NET Framework 3.5 podporuje programování s vlákny a poskytuje také bohatou sadu programových nástrojů na vláknech založenou. Jejich stručné představení nám umožní lépe pochopit kontext, do kterého zapadá knihovna Parallel FX, které se budeme věnovat dále. Podrobnější popis zde jmenovaných prvků lze najít např. v [2], částečně také v [1,5]. 2.1 Procesy, aplikační domény a vlákna.net přebírá funkcionalitu procesů a vláken z operačního systému Windows. Přidává k tomu prvek aplikační doména jakožto jakýsi podproces, který fyzicky existuje v rámci nějakého procesu v systému, ale z hlediska virtuálního stroje.netu jde o samostatnou jednotku. (Díky řízené paměti na sebe aplikační domény nevidí, přestože sdílejí jeden adresový prostor v rámci jednoho procesu, kde spolu žijí.) 2.2 Systémové synchronizační a komunikační prvky Kromě samotných procesů a vláken přebírá.net z operačního systému i jeho synchronizační a komunikační prvky, jmenovitě například princip čekatelných objektů, mutexy, semafory, vláknovou afinitu, signály, časovače a roury. Všechny tyto prvky jsou v.netu implementovány jako objekty v základní knihovně a je možno je jednoduše použít v libovolném programovacím jazyce. (V.NETu nelze používat sdílení paměti mezi procesy mapováním souboru do paměti, neboť v řízeném prostředí neexistuje pojem paměťová adresa.) Ačkoliv se tyto systémové prvky v.netu vyskytují jako objekty, z principu své nízkoúrovňové funkcionality nijak neošetřují to, jestli je programátor používá správně, a proto při jejich použití vzniká řada (lidských) chyb. Dalšími základními prvky převzatými z operačního systému jsou tzv. interlocked neboli blokované operace. Jedná se o sadu velmi jednoduchých operací, které lze s pomocí hardwaru provádět atomicky. Jejich použití je proto výrazně rychlejší, než použití prvků výše jmenovaných (jejichž společnou vlastností je, že využívají jistý typ zámku či zamykání a právě proto jsou relativně pomalé). Poznámka. Blokované operace jsou synchronizační prvky na nejnižším stupni abstrakce, jsou to jednotlivé instrukce procesoru (např. přičtení jedničky, compareand-swap atd.) Systém pomocí těchto operací implementuje všechny složitější prvky (jako např. semafor).

2.3 Monitory a signály. ETu Zatímco v čistém Windows se k synchronizaci vláken běžně používají především výše zmíněné mutexy, semafory a signály (a také kritické sekce, které.net na rozdíl od Windows nerozlišuje od mutexů), v objektově orientovaném prostředí.netu se nejvíce využívá jeho objektový synchronizační prvek monitor. Jde o prvek na vyšší úrovni abstrakce, který je oblíbený v objektově orientovaných prostředích pro jeho jednoduchý způsob použití a poměrně velké možnosti, kdy obvykle poslouží jako elegantní zámek či signál. Další výhodou objektových monitorů je, že způsob, jakým se v kódu používají, prakticky vylučuje různé typy chyb, kterých se programátoři mohou dopustit při používání klasických neobjektových konstruktů zmíněných výše. Jazyky C# a Visual Basic mají pro monitory dokonce i zvláštní syntaktickou podporu usnadňující jejich použití (jakoby navíc, protože monitory jakožto objekty samozřejmě lze použít i bez této speciální syntaxe). 2.4 Další nástroje pro asynchronní programování Na závěr této kapitoly si ještě ukažme (alespoň několik nejdůležitějších) nástrojů pro asynchronní programování na vyšší úrovni abstrakce, které.net nabízí. Fond vláken. Každý proces.netu obsahuje tzv. fond vláken (thread pool), který udržuje sadu vláken a poskytuje je pro provádění různých operací na pozadí. Fond vláken je k dispozici jak samotnému systému.netu, tak aplikaci. Výhodou fondu je, že recykluje tatáž vlákna a odpadá tak časově náročné zakládání a ukončování vláken. Vykonání nějaké operace na pozadí je také díky fondu jednodušší nemusíme se starat o objekt vlákna, stačí jednoduše dodat fondu funkci, kterou chceme vykonat (ve formě delegátu). Čtenáři a písaři. Kromě obyčejného zámku nabízí.net i zámek pro čtenáře a písaře umožňující souběh při čtení, ale vyžadující exkluzivitu při zápisu. K dispozici jsou dokonce dvě velmi odlišné implementace, lišící se funkcionalitou i rychlostí. Asynchronní programový model. Systém Windows nabízí možnost asynchronního čtení a zápisu souborů, kdy aplikace dá povel k zahájení operace a pomocí APC je jí potom oznámeno dokončení této operace. Tento způsob práce se soubory nepoužívá vlákna, má proto menší režii a v důsledku je rychlejší než použití vláken. (APC je speciální systémová podpora pro asynchronní volání bez vláken a používá se zde pro oznamování dokončení operace.).net zobecňuje asynchronní práci se soubory na obecný asynchronní programový model (APM) a v základní knihovně proto najdeme různé třídy, které toto podporují (není přitom řečeno, jak je funkcionalita implementována, APM definuje jen vnější rozhraní). APM je tedy vestavěná podpora k provádění déletrvajících operací asynchronně, obvykle (ale ne nutně) pomocí vláken.

Asynchronní aktualizace GUI. Okna či obecně prvky grafického uživatelského rozhraní ve Windows musejí být obsluhovány vždy tím vláknem, kterým byly vytvořeny. To samozřejmě komplikuje používání vláken v běžných aplikacích,.net proto nabízí jednoduchou metodu asynchronního volání metod na objektech uživatelského rozhraní. (Vnitřně je implementováno pomocí systémové fronty zpráv.) Background worker. Dalším prvkem sloužícím k usnadnění práce s GUI je background worker zvláštní typ vlákna, které umí komunikovat s oknem. Tato třída umožňuje komunikaci mezi vláknem GUI a vláknem na pozadí pomocí speciálních objektů událostí, které překračují hranice vlákna. (Čili jedno vlákno aktivuje událost, ale signál o události přichází jinému vláknu. Toto přenesení mezi vlákny je přitom zcela transparentní.) 3 Parallel FX Parallel FX, někdy označována také delším názvem Parallel Extensions to the.net Framework, je knihovna pro.net Framework 3.5 přidávající do.netu možnost paralelního programování na ještě vyšší úrovni abstrakce než u konstruktů popsaných v předchozí kapitole. Jelikož jde o řízenou knihovnu, je možno ji použít ve všech programovacích jazycích.netu. Základním zdrojem informací o Parallel FX je přímo jeho oficiální dokumentace [3]. Parallel FX nabízí v rámci jedné knihovny tři různé způsoby paralelizace: Deklarativní paralelizace dat Imperativní paralelizace dat Imperativní paralelizace úloh Ve všech případech pracujeme na vyšší úrovni abstrakce a nestaráme se o vlákna. Na rozdíl od například fondu vláken, kde také můžeme zadávat úlohy k vykonání a nestarat se o jednotlivá vlákna, Parallel FX používá vlastní řízení běhu, kdy se snaží nasazovat tolik vláken, kolik je k dispozici výpočetních uzlů (jader procesoru). 3.1 Deklarativní paralelizace PLI Q Část Parallel FX umožňující deklarativní paralelizaci programu se oficiálně nazývá PLINQ (Parallel Language Integrated Query) a je implementovaná jako rozšíření standardní knihovny LINQ v jmenném prostoru System.Linq. Smyslem a hlavní výhodou deklarativního přístupu k paralelizaci je, že programátor definuje pouze co chce spočítat, a ne jak to chce spočítat. Použití PLINQ je velmi snadné, protože vše je elegantně zakomponováno do standardního LINQ a na první pohled není rozdíl mezi PLINQ a LINQ téměř ani poznat. Nejprve se podívejme na PLINQ z hlediska uživatele. Pomocí rozšiřující metody AsParallel je možno převést každou kolekci typu IEnumerable na kolekci typu IParallelEnumerable připravenou pro zpracování pomocí PLINQ. Potom již můžeme použít standardní techniky LINQ a kód bude proveden paralelně.

Pro příklad si uveďme kód, který vyfiltruje z kolekce slov jen ta obsahující písmeno 'a' a převede tato slova na velká písmena. string[] data; var data2 = from d in data.asparallel() where d.contains("a") select d.toupper(); foreach(var d in data2) Console.WriteLine(d); Že se kód provede skutečně paralelně, je možno ověřit přímo na tomto příkladu tím, že výsledné pořadí slov bude jiné než ve zdrojovém poli. Potřebujeme-li však pořadí zachovat, můžeme použít modifikátor AsOrdered. Je to rozšiřující metoda na typu IParallelEnumerable, lze ji tedy vložit kamkoliv, kde chceme pořadí zachovat. Vynucení pořadí tímto způsobem nám pochopitelně snižuje výpočetní výkon, pomocí AsUnordered je možné vynucení pořadí opět zrušit. Dále pak máme k dispozici ještě AsSequential, kterým můžeme převést IParallelEnumerable zpět na IEnumerable a vypnout tak paralelní zpracování. Tyto převodní metody v praxi můžeme podle potřeby kombinovat a optimalizovat tak provádění LINQ dotazů. PLI Q pod pokličkou Funkcionalita PLINQ je implementována jako sada rozšiřujících metod ve třídě System.Linq.ParallelEnumerable, která de facto implementuje paralelní verzi třídy System.Linq.Enumerable z LINQ. Zatímco třída Enumerable implementuje LINQ nad běžnými kolekcemi typu IEnumerable a IEnumerable<T>, třída ParallelEnumerable implementuje LINQ (neboli PLINQ) nad kolekcemi typu IParallelEnumerable či IParallelEnumerable<T>. Pomocná statická třída ParallelQuery implementuje rozšiřující metodu AsParallel, která přijme IEnumerable či IEnumerable<T> a vrací jemu odpovídající IParallelEnumerable či IParallelEnumerable<T>. Stejně tak další výše uvedené rozšiřující metody AsOrdered, AsUnordered a AsSequential jsou implementovány ve třídě ParallelQuery. PLINQ se tedy chová stejně jako LINQ nad objektovými kolekcemi. Pomocí převodních metod v ParallelQuery je možno LINQ a PLINQ libovolně kombinovat. Například vynucení pořadí voláním AsOrdered zpomalí paralelní výpočet, takže jej vložíme jen tam, kde pořadí skutečně nutně potřebujeme, a pak jej opět zrušíme vložením AsUnordered. Ne ve všech situacích je PLINQ vhodný, protože kód který má nějaký vedlejší efekt (tj. kromě vrácení návratové hodnoty dělá i něco bokem) bude zřejmě trpět právě zmíněným nezachováním pořadí. Dále pak kód přistupující ke GUI nemůže používat více vláken, kód pracující se soubory je pravděpodobně rychlostně limitován právě diskovým systémem a PLINQ ho nijak nezrychlí (jen zbytečně zatíží procesor více vlákny) atd. 3.2 Imperativní paralelizace Task Parallel Library Část Parallel FX umožňující imperativní paralelizaci se oficiálně nazývá Task Parallel Library a najdeme ji v jmenných prostorech System.Threading a System.Threading.Tasks.

Třída Parallel Třída Parallel poskytuje sadu statických metod For, ForEach a Invoke. Jejich význam je patrný již z názvu, ukažme si jednoduché příklady použití: Parallel.For(0, 100, i => results[i] = Compute(i)); - naplní pole o 100 prvcích výsledky volání funkce Compute s příslušným indexem do pole Parallel.ForEach(data, c => Compute(c)); - volá funkci Compute pro každý prvek kolekce data static void WalkTree<T>(Tree<T> tree, Action<T> func) { if (tree == null) return; Parallel.Invoke( () => WalkTree(tree.Left, func), () => WalkTree(tree.Right, func), () => func(tree.data)); } - funkce pro rekurzivní průchod binárním stromem Parallel.ForEach je v obecném případě méně efektivní než Parallel.For, protože všechna vlákna musejí přistupovat ke společnému enumerátoru. Výjimkou jsou kolekce podporující rozhraní IList<T>, které Parallel.ForEach rozpozná a použije pro ně efektivnější implementaci. Třída Task Třída Parallel interně používá objekty třídy Task, kterou můžeme použít i přímo. Voláním Task.Create(delegát) vytvoříme novou úlohu k asynchronnímu vykonání, jde tedy o podobný princip jako u fondu vláken, na rozdíl od fondu zde však dostaneme k dispozici objekt úlohy, se kterým lze dále pracovat. Například můžeme snadno čekat na dokončení úlohy pomocí metody Wait (funguje stejně jako Join u vláken) nebo jednoduše čekat rovnou na skupinu úloh pomocí WaitAll. Úlohu čekající ve frontě na spuštění lze zrušit voláním Cancel. Běžící úloha se tímto voláním neodstřelí, ale je nastaven příznak IsCancelled a sama úloha jej musí pravidelně testovat, aby zjistila, že bylo Cancel použito. (Toto chování je tedy stejné jako u výše popsané třídy BackgroundWorker.) Důležitou vlastností úlohy typu Task je, že když spouštíme novou úlohu z úlohy, tak systém si pamatuje jejich vztah rodič potomek a výpočet rodičovské úlohy není považován za dokončený, dokud nejsou dokončeny všichni její potomkové. Toto se projeví například při použití Wait když čekáme na dokončení úlohy, tak vždy včetně všech jejích potomků.

Třída Future<T> Třída Future<T> je specializací (tj. potomkem) třídy Task. Je to úloha s výslednou (návratovou) hodnotou. Vytvoříme ji stejně jako Task (tj. voláním Create) a potom můžeme pomocí property Value zjistit výslednou hodnotu. Budeme-li Value číst dříve, než skončí vykonání úlohy, pak jde o blokující operaci. Bude-li však hodnota již spočítaná, objekt Future<T> si ji pamatuje a skrze Value rovnou vrací. Příkladem využití může být zjištění počtu uzlů v binárním stromu: int CountNodes(Tree<T> node) { if (node == null) return 0; var left = Future.Create(() => CountNodes(node.Left)); int right = CountNodes(node.Right); return 1 + left.value + right; } Poznámka. Na rozdíl od přímého použití vláken zde každé volání Future.Create nevytváří nové vlákno. Počet vláken řídí manažer úloh Parallel FX a pro dosažení nejlepších výsledků je v takovém algoritmu vhodné od jisté úrovně vnoření přejít na sekvenční rekurzivní funkci, protože úloh v ten okamžik již bude vytvořeno dost a vytváření dalších nových úloh zabere nějaký výpočetní čas, ale přitom na běžném počítači o několika málo výpočetních uzlech výkon už dále nezvýší. ContinueWith Task i Future<T> mají jednu velice zajímavou možnost voláním ContinueWith můžeme určit pokračování, čili co se má vykonat po dokončení dané úlohy. Tato metoda navíc vrací opět objekt typu Task nebo u Future<T> volitelně i Future<T>, takže je možno vytvářet i delší řetězy úloh. Pomocí dalších parametrů v metodě ContinueWith lze také upravit chování tohoto pokračování detailněji. Princip pokračování vytváří opět ještě vyšší úroveň abstrakce a je pomocí něj možno vytvářet celou řadu složitějších algoritmů, pro další informace viz např. [4]. 3.3 Synchronizační nástroje Parallel FX nabízí také řadu synchronizačních prvků na vyšší úrovni abstrakce, než jsou klasické mutexy, semafory apod. Najdeme je ve jmenném prostoru System.Threading a z principu nejsou přímo závislé na způsobu implementace paralelizmu, takže je lze používat jak s klasickými vlákny, tak s výše popsanými úlohami Parallel FX. CountDownEvent Třída CountDownEvent je zobecněním události ManualResetEvent. Jak už napovídá název, tuto událost je třeba jakoby vícekrát signalizovat, než je probuzeno vlákno, které na ni čeká. Třída Má metodu Decrement, která sníží počítadlo a teprve při dosažení nuly je událost skutečně signalizována. K dispozici je i metoda Increment, kterou je možno počítadlo naopak zvýšit, pokud událost ještě nebyla signalizována.

CountDownEvent se hodí zejména při operacích typu fork/join (pro implementaci bariéry). Poznámka. Stejně jako u ManualResetEvent, tento signál není možno resetovat a znovu použít dřív, než je vykonán kód všech čekajících vláken (protože by k nim signál nedorazil). LazyInit<T> Třída LazyInit<T> implementuje vláknově bezpečný způsob zpožděné inicializace proměnné. Hodí se pro situace, kdy chceme proměnnou inicializovat až při prvním použití. V sekvenčním programu stačí pro přístup k proměnné vytvořit property a vložit kód v podobě if(hodnota == null) hodnota = new Třída(); return hodnota;. Pomocí LazyInit<T> dosáhneme stejné funkcionality i v paralelním programu. Vlákna mohou o inicializaci proměnné soupeřit (tj. více vláken se současně může pokoušet o inicializaci a vytvořit tak více instancí, z nichž jen jedna nakonec bude uložena v naší proměnné). Toto chování však lze i zakázat (parametrem konstruktoru), pokud nám nevyhovuje. Dále je také možno určit proměnnou jako thread-local, tj. aby byla samostatná instance pro každé vlákno. ManualResetEventSlim, SemaphoreSlim Třída ManualResetEventSlim je obdobou systémové třídy události ManualResetEvent. Má lehce zúženou funkcionalitu (nemůže být použita mezi procesy), naopak výhodou slim verze je vyšší rychlost, protože běží většinou jen v user módu (zatímco systémové synchronizační prvky pracují v kernel módu procesoru). Podobně také třída SemaphoreSlim je náhradou za systémovou třídu Semaphore. SpinLock, SpinWait Třída SpinLock implementuje zámek podobně jako monitor (operace Enter a Exit), ale používá aktivní čekání. Třída SpinWait implementuje spin pro spin lock. Třída se používá tak, že opakovaně voláme metodu SpinOnce. Rozhodnutí, kdy se metoda hned vrátí a kdy předá řízení jinému vláknu, je skryto uvnitř SpinWait. WriteOnce<T> Generická třída WriteOnce<T> implementuje proměnnou, kterou je možno zapsat jen jednou, a pak už ji lze jen číst. Hodnota proměnné je přístupná skrze property Value. Zjistit, zda je již hodnota nastavena, lze pomocí property HasValue. Při špatném použití (opakovaný zápis nebo čtení před zápisem) je vyhozena výjimka. 3.4 Vláknově bezpečné kolekce ConcurrentQueue<T> a ConcurrentStack<T>

Parallel FX implementuje ve jmenném prostoru System.Threading.Collections vláknově bezpečné kolekce ConcurrentQueue<T> a ConcurrentStack<T>. Pro příklad uveďme, jak vybrat a zpracovat všechny prvky fronty: Data d; while(queue.trydequeue(out d)) Process(d); Vkládání prvků je stejné jako u klasických kolekcí, ale pro vybírání prvků zde není metoda Dequeue (resp. Push u zásobníku), ale pouze metoda TryDequeue (resp. TryPush u zásobníku), která vrací příznak úspěchu a načtenou hodnotu pak jako out referenci. BlockingCollection<T> Pro implementaci scénářů typu dodavatel odběratel je určena třída BlockingCollection<T>. Sama žádnou kolekci neimplementuje, funguje jen jako obálka (wrapper) nad jinými třídami kolekcí implementujícími IConcurrentCollection<T> (což jsou například výše uvedené ConcurrentQueue<T> a ConcurrentStack<T>). Blokující kolekce má tři základní schopnosti: V konstruktoru lze nastavit maximální počet prvků v kolekci. Když je pak kolekce plná, přidání prvku voláním Add je blokující operace. Odebrání prvku voláním Remove je blokující operace, pokud je kolekce prázdná. Dodavatel může voláním CompleteAdding oznámit, že už žádné další prvky nebudou dodány. Odebrání prvku pak už není blokující, ale oznamuje, že další prvky už nebudou. K dispozici jsou také property IsAddingCompleted pro zjištění, jestli už byly všechny prvky přidány, a IsCompleted pro zjištění, zda už byly všechny prvky přidány i odebrány. Při používání této funkcionality je vhodnější odebírat prvky pomocí TryRemove, neboť Remove vyhodí výjimku, pokud je fronta prázdná a další prvky už ani nebudou (což ovšem lze brát i za výhodu). BlockingCollection<T> poskytuje také sadu metod pro přidávání a odebírání prvků z řady kolekcí ve stylu vlož kamkoliv a odeber odkudkoliv tyto jsou vhodné při větší zátěži, neboť použitím více kolekcí současně se vyhneme celé řadě zamykání a získáme tak vyšší celkový výkon. Zajímavá je také metoda GetConsumingEnumerable, která vrací standardní enumerátoru typu IEnumerable<T>, takže odběratele pak můžeme implementovat pomocí obyčejného příkazu foreach a výrazně tak zjednodušit paralelní program. (Dokumentace Parallel FX nevysvětluje, jak je toto implementováno. Enumerátor má zřejmě blokující operaci MoveNext, díky čemuž může kontrolovat prázdnost kolekce i skončení dodávek.) 3.5 Výjimky Zajímavým a problematickým tématem při paralelním zpracování je otázka výjimek. Pracujeme-li s vlákny přímo (tj. po staru ), můžeme výjimky zachytávat v každém

vlákně zvlášť. Metody paralelního programování na vyšší úrovni abstrakce, speciálně pak PLINQ, však často nemají explicitně definován kód pro vlákna a je tedy vhodnější, aby i výjimky byly zachytávány jen jedním vláknem. V paralelním kódu využívajícím Parallel FX samozřejmě můžeme libovolně používat konstrukce try catch finally. Vyskytne-li se však neošetřená výjimka v paralelně zpracovávaném kódu, systém se k ní staví zvláštním způsobem předá ji do hlavního vlákna, které zahájilo paralelní operaci. Při paralelním výpočtu pomocí PLINQ nebo Task Parallel Library přitom může nastat celá řada výjimek téměř současně. Parallel FX se při první výjimce snaží ihned zastavit výpočty ve všech vláknech a další již nestartuje. I tak ale může nastat více výjimek současně a tyto výjimky systém slučuje do jediné výjimky typu System.Threading.AggregateException, kterou pak propaguje do vlákna, které paralelní výpočet spustilo. Jednotlivé výjimky jsou přístupné pomocí property InnerExceptions. Poznámka. PLINQ odkládá vyhodnocení dotazu až k procházení výsledné kolekce. Pro zachycení výjimky PLINQ je tedy třeba uzavřít do try catch bloku ne volání PLINQ, ale až procházení výsledné kolekce. (Toto se může zdát matoucí, ale je to stejné jako u klasického sekvenčního LINQ.) 4 Zhodnocení Knihovna Parallel FX je jistě zajímavým rozšířením platformy.net ve verzi 3.5. Zatím je distribuována samostatně jako preview a zřejmě se objeví přímo jako součást některé z příštích verzí.net Frameworku, protože paralelní programování je dnes velmi důležitým tématem z důvodu rozšiřování vícejádrových procesorů. V tomto příspěvku jsme si představili všechny součásti aktuální verze Parallel FX, diskutovány nebyly jen věci týkající se systémových nastavení, kterými je možno ovlivnit chování vnitřního plánovače úloh, který Parallel FX používá. (Jedná se o převážně kooperativní plánovač úloh typu Task, nad kterými je Parallel FX postaven. Tento plánovač je stále ve vývoji a nemá proto smysl zabývat se podrobnostmi současné verze.) V určitých speciálních případech může být vhodné přímo ručně programovat s vlákny, můžeme tak totiž aplikaci ušít na míru a dosáhnout tedy největšího výkonu. V mnoha případech je však výhodnější použít některý z konstruktů na vyšší úrovni abstrakce, které nabízí Parallel FX. Proces vytváření softwaru tak bude rychlejší a paralelní způsob výpočtu dokážeme v praxi použít na daleko více místech i bez letité praxe v této oblasti programování. Reference 1. Duffy J. Professional. ET Framework 2.0. Wrox Press, 2006. ISBN 0-7645- 7135-4, ISBN-13: 978-0-7645-7135-0. 2. Keprt A. Systémové programování v jazyce C#. Studijní text pro distanční vzdělávání (e-book), Univerzita Palackého, Olomouc, 2008.

3. Microsoft Parallel Extensions to the. ET Framework 3.5 June 2008 Community Technology Preview (CTP). chm nápověda, dostupná ze serveru http://www.microsoft.com/downloads/ 4. Toub S. Useful Abstractions Enabled with ContinueWith. V blogu: Parallel Programming in. ET. http://blogs.msdn.com/pfxteam/archive/2008/07/23/8768673.aspx 5. Troelsen A. Pro C# 2008 and the. ET 3.5 Platform, 4.vydání. Apress, 2007. 1370pp., ISBN 1-59059-884-9, 978-1-59059-884-9. Annotation: Parallel FX and parallel programming in. ET Framework Parallel FX library is an official extension to the.net Framework aimed at parallel programming with threads and shared memory. It brings new parallel object oriented programming techniques on a higher level of abstraction. This paper briefly introduces Parallel FX and tries to put it into context of other thread based parallel programming techniques in Windows and Microsoft.NET Framework. Parallel programming is a very current topic, especially with regard to emerging new multicore processors, and this trend won t surely change in the near future. In contrast to this, most current computer programs don t explicitly use multicore processors in their computing algorithms, and also teaching of algorithms still focuses mainly to sequential/imperative models of programming and algorithms. Real world parallel computing is almost completely limited to one single instrument: divide & conquer principle and explicit usage of threads. Parallel FX is a new framework of Microsoft which offers a few new ways of parallelization, theoretically known before but never used so widely in a massively used programming environment like.net. Parallel FX moves the workload related to thread programming from application programmer to the framework itself. This paper introduces Parallel FX and its computation models. Next, it discusses the usability of this new technology in real world applications.