Paralelní programování a .NET 4.0
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu
Reklama

Paralelní programování a .NET 4.0Paralelní programování a .NET 4.0

 

Paralelní programování a .NET 4.0

Google       Google       28. 8. 2010       22 067×

Nová verze populárního frameworku .NET se v našich počítačích ještě ani pořádně neohřála, a tak je teď ta nejvhodnější chvíle představit si zajímavé novinky z oblasti paralelního programování a multithreadingu.

Reklama
Reklama

Na světě dnes již převládají multi-core počítače, počínaje těmi osazenými procesory Core 2 Duo a nejmodernějšími Intel i7 konče. Logickým krokem je pak využití všech dostupných jader, aby naše aplikace mohla zpracovávat více úloh najednou. Samozřejmě, podpora více vláken je v .NET Frameworku už pěknou řádku let, ale kvůli své složitosti to není příliš oblíbené téma. Ono se není ani čemu divit, je potřeba dávat si pozor na velké množství věcí, jen se podívejte na můj seriál o multithreadingu zde na Programujte.

Vývojáři .NET 4.0 se tak pokusili alespoň částečně vyřešit tento problém přidáním nových knihoven souhrnně zvaných „Parallel Extensions“. Tato rozšíření („extensions“) mají dvě části - Task Parallel Library (TPL) a PLINQ (Parallel LINQ). PLINQ ve skutečnosti vnitřně pro svou funkčnost používá TPL. TPL je složena z několika nových API převážně v namespace System.Threading.Tasks.

Na začátek je potřeba jedno malé vysvětlení – jaký je rozdíl mezi multithreadingem a paralelismem? Paralelní programování je ve skutečnosti multithreading (tedy používá vlákna), ale samotným pojmem multithreading se spíše myslí používání vláken na různé nesouvisející úkony (tedy že jedno vlákno se stará o uživatelské rozhraní, druhé počítá číslo pí atp.). Na druhou stranu paralelismus znamená, že jednu složitou akci rozdělíme na více vláken.

Pojďme se podívat na pár příkladů, jak Parallel Extensions využít. Začneme knihovnou TPL.

Něco snadného – paralelní cykly

Měli jste někdy kolekci s tisíci objektů, kterými jste museli procházet, a říkali jste si „jen kdyby to šlo snadno rozdělit na víc vláken“? Teď už si to říkat nemusíte, nemusíte vědět ani nic o multithreadingu, stačí jen použít trochu jinou verzi cyklu for nebo foreach. Kód řekne víc než tisíc slov (a nejdříve nezapomeňte vložit jmenný prostor System.Threading.Tasks):

// standardní sekvenční přístup
foreach (var i in list)
{
    Console.WriteLine(i);
}
            
// paralelní přístup
Parallel.ForEach(list, i => Console.WriteLine(i));

V zásadě to funguje poměrně snadno. TPL vezme kolekci, rozdělí ji na několik částí, vytvoří několik vláken a jednotlivá vlákna se pak starají o jednotlivé části kolekce. A to aniž byste vy, jakožto vývojáři, museli napsat jediný řádek pro vytvoření vlákna nebo něčeho podobného.

Metoda For() funguje obdobně:

// vypíše čísla {0,1,2}
Parallel.For(0,3, i => Console.WriteLine(i));

Vlákna jsou přeci jenom trochu složitější tématika, a tak se může stát, že se dostaneme do složitější situace, kdy bychom si chtěli fungování těchto dvou metod trochu upravit k obrazu svému. I na to bylo pomyšleno, a proto mají obě metody velké množství přetížených verzí, více o nich na MSDN.

O stupínek těžší – paralelizace úkolů

Task Parallel Library. To by mělo mít něco společného s úkoly, neříkáte si? A taky že má, „úkol“ stojí přímo ve středu funkčnosti této nové knihovny. Pod slovem „úkol“ si můžeme představit nějakou asynchronní akci, vlastně něco, pro co bychom v „obyčejném“ multithreadingu vytvořili nové vlákno.

Pro kohokoliv, kdo kdy zkusil práci s vlákny, musí být výhody hned jasné:

  • Automatická správa ThreadPoolu (zjednodušeně řečeno je to místo, odkud se berou vlákna), všem úkolům, které zařadíme do fronty je postupně přiřazeno vlákno. To vše je děláno s ohledem na největší efektivitu.
  • Lepší a pohodlnější kontrola, než je možná s klasickými vlákny – okolo úkolů je postaveno bohaté API, které poskytuje další úroveň abstrakce nad běžnými vlákny.

V základu máme dva způsoby, jak vykonávat úkoly – implicitně a explicitně.

Implicitní vykonávání úkolů

Pro implicitní vykonávání slouží metoda Parallel.Invoke(). Dává nám hezkou cestu, jak spouštět jednoduše několik metod najednou, stačí jen několik delegátů odkazujících na jednotlivé statické metody. Následující příklad ukazuje tři různé způsoby, jak toho docílit, a vězte, že jich je ještě víc. V praxi je ovšem ideální se držet jen jednoho, kvůli přehlednosti:

Parallel.Invoke(() => NejakaPrace(), 
    new Action(NejakaDalsiPrace),
    delegate() { Console.WriteLine("třetí způsob"); });

Pokud bychom chtěli trochu víc možností, musíme vykonávat úkoly explicitně.

Explicitní vykonávání úkolů

Úkol je reprezentován instancí třídy System.Threading.Tasks.Task. Pokud vrací po svém splnění nějakou hodnotu, použijeme odvozenou třídu Task. Obě třídy poskytují množství metod a vlastností, například si uveďme vlastnost Status, která nám řekne, jestli byl už úkol spuštěn, jestli skončil s chybou, jestli byl zrušen apod.

Úkol vytváříme pomocí delegátu, který obaluje kód úkolu:

var prvniUkol = new Task(() => Console.WriteLine("Zdraví vás první úkol!"));
prvniUkol.Start();

Console.WriteLine("Tady vás zdraví hlavní vlákno");
Console.WriteLine("Je už úkol dokončen? " + prvniUkol.IsCompleted); 

Když si tento kód párkrát spustíte, zjistíte, že bude na otázku „Je už úkol dokončen?“ střídavě odpovídat true/false. Můžete to brát jako důkaz toho, že je úkol skutečně spuštěn na jiném vlákně a jednou je rychlejší ono, podruhé zase to hlavní.

Úkoly můžeme vytvářet i spouštět v jednom kroku, jak ukazuje tento kód:

var prvniUkol = Task.Factory.StartNew(() => Console.WriteLine("Zdraví vás první úkol!"));

Vlastnost Factory použitá v kódu výše rozhodně stojí za pozornost. Tato vlastnost vrací instanci třídy TaskFactory a pomocí ní pak voláme metodu StartNew(). Není to ale jediná metoda, kterou máme k dispozici, zajímavá je například i ContinueWhenAll(), která přijímá sadu úkolů, po jejichž ukončení bude spuštěn jiný úkol.

Vraťme se teď trochu zpátky k odvozené třídě Task, která nám umožňuje vracet po ukončení úkolu data. Následuje příklad:

Task<double>[] ukoly = new Task<double>[]
{
    Task.Factory.StartNew(() => Pocitej1()),
    Task.Factory.StartNew(() => Pocitej2()),
    Task.Factory.StartNew(() => Pocitej3())                
};

double[] vysledky = new double[ukoly.Length];
            
for (int i = 0; i < ukoly.Length; i++)
    vysledky[i] = ukoly[i].Result;

Není to nic složitého: na začátku vytvoříme pole úkolů, do kterého rovnou tři umístíme a rovnou je spustíme. Pak si vytvoříme nové pole („vysledky“), do kterého budeme ukládat hodnoty vrácené úkoly. Každý úkol odvozený od třídy Task<TResult> poskytuje vlastnost Result, která po jeho skončení obsahuje výsledek, a toho využijeme na konci kódu. Metody Pocitej1, 2 a 3 jsou jen statické metody, které něco počítají a pak vrací hodnotu typu double.

To byla jen stručná ukázka možností knihovny Task Parallel Library. Uvedené příklady by vám měly pomoci s paralelizací alespoň těch nejjednodušších úloh. Teď přichází na řadu Parallel LINQ.

Parallel LINQ - použití

Pokud se dotazujete velkého množství dat pomocí LINQ, kdy už by se paralelizaci vyplatilo využít, je nasazení PLINQ většinou hračka.

PLINQ totiž podporuje úplně všechny operátory jako LINQ a stejně jako LINQ používá tzv. „deferred execution“ (překlad „opožděné volání“ je asi nejvýstižnější). Znamená to, že dotaz není zavolán hned při deklaraci, ale až při jeho použití dál v kódu (například ve chvíli, kdy se na data zeptáme pomocí cyklu foreach apod.).

Dobře, ale jak na to? Stačí zavolat metodu AsParallel() na cílovou kolekci uvnitř dotazu a je hotovo! Porovnejte následující dva kousky kódu, první pomocí klasického LINQ a druhý pomocí PLINQ:

List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var query_linq = from i in list
            where i % 2 == 0
            select i;

var query_plinq = from i in list.AsParallel()
                    where i % 2 == 0
                    select i;

Toto byl ten nejjednodušší příklad použití, který by měl pro množství situací stačit. Pochopitelně máme k dispozici spoustu nejrůznějších nastavení a možností, například jak omezit počet použitých jader procesoru, jak ošetřovat výjimky, jak zastavovat volání dotazů a tak dále. Zmíněné věci by si zasloužily spíše svůj článek, proto si o nich povíme někdy příště. Doufám, že vám článek ukázal některé ze zajímavých novinek v .NET 4.0.

×Odeslání článku na tvůj Kindle

Zadej svůj Kindle e-mail a my ti pošleme článek na tvůj Kindle.
Musíš mít povolený příjem obsahu do svého Kindle z naší e-mailové adresy kindle@programujte.com.

E-mailová adresa (např. novak@kindle.com):

TIP: Pokud chceš dostávat naše články každé ráno do svého Kindle, koukni do sekce Články do Kindle.

1 názor  —  1 nový  
Hlasování bylo ukončeno    
0 hlasů
Google
(fotka) Jakub KottnauerJakub studuje informatiku na FIT ČVUT, jeho oblíbenou platformou je .NET.
Web     Twitter     Facebook     LinkedIn    

Nové články

Obrázek ke článku Malware KONNI se úspěšně skrýval 3 roky. Odhalil ho bezpečnostní tým Cisco Talos

Malware KONNI se úspěšně skrýval 3 roky. Odhalil ho bezpečnostní tým Cisco Talos

Bezpečnostní tým Cisco Talos odhalil celkem 4 kampaně dosud neobjeveného malwaru, který dostal jméno KONNI. Ten se dokázal úspěšně maskovat od roku 2014. Zpočátku se malware zaměřoval pouze na krádeže citlivých dat. Za 3 roky se ale několikrát vyvinul, přičemž jeho současná verze umožňuje útočníkovi z infikovaného počítače nejenom krást data, ale i mapovat stisky na klávesnici, pořizovat screenshoty obrazovky či v zařízení spustit libovolný kód. Pro odvedení pozornosti oběti zasílali útočníci v příloze také obrázek, zprávu a výhružkách severokorejského režimu či kontakty na členy mezinárodních organizací.

Reklama
Reklama
Obrázek ke článku Pouze jedna z deseti lokálních firem ví o pokutách plynoucích z GDPR

Pouze jedna z deseti lokálních firem ví o pokutách plynoucích z GDPR

Trend Micro, celosvětový lídr v oblasti bezpečnostních řešení a VMware, přední světový dodavatel cloudové infrastruktury a řešení pro podnikovou mobilitu, oznámily výsledky výzkumu mezi českými a slovenskými manažery zodpovědnými za ochranu osobních údajů, který zjišťoval, jak jsou připraveni na nové nařízení o ochraně osobních údajů (GDPR). Většina firem v České republice a na Slovensku nad 100 zaměstnanců je již s novým nařízením GDPR obeznámena. Výzkum provedený ve spolupráci s agenturou Ipsos ukázal, že téměř 8 firem z 10 o nařízení ví, přičemž jeho znalost je o něco vyšší na Slovensku (89 %) než v České republice (69 %).

Obrázek ke článku Vyděračský software Locky se vrací, tváří se jako potvrzení platby, odhalil tým Cisco Talos

Vyděračský software Locky se vrací, tváří se jako potvrzení platby, odhalil tým Cisco Talos

Jeden z nejznámějších ransomwarů, Locky, se vrací. Po většinu roku 2016 patřil mezi nejrozšířenější vyděračské softwary. Ke svému šíření využíval emailové kampaně s infikovanými přílohami. Ransomware Locky byl rozesílán prostřednictvím botnetu (internetový robot zasílající spamy) Necurs. Jeho aktivita na konci roku 2016 téměř upadla a spolu s ní i šíření ransomwaru Locky. Před několika týdny se Necurs opět probudil a začal posílat spamy nabízející výhodný nákup akcií. Dne 21. dubna zaznamenal bezpečnostní tým Cisco Talos první velkou kampaň ransomwaru Locky prostřednictvím botnetu Necurs za posledních několik měsíců.

Obrázek ke článku Dovozci baterií mění logistiku, letadlo nahrazuje námořní doprava

Dovozci baterií mění logistiku, letadlo nahrazuje námořní doprava

Dovozci baterií do mobilů či notebooků upouštějí od letecké přepravy zboží. V letošním roce plánují dovézt až 80 % produktů lodí. Přitom před 5 lety byla většina baterií do mobilních přístrojů dovezených do České republiky přepravována letadlem. Za proměnou způsobu transportu akumulátorů stojí zpřísnění pravidel pro leteckou přepravu, která přinášejí vyšší náklady i náročnou agendu.

loadingtransparent (function() { var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; po.src = 'https://apis.google.com/js/plusone.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); })();
Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032017 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý