Paralelní programování a .NET 4.0
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu
Reklama
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       21 849×

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

Reklama
Reklama
Obrázek ke článku Nový IT hráč na českém trhu

Nový IT hráč na českém trhu

V roce 2015 otevřela v Praze na Pankráci v budově City Tower své kanceláře společnost EPAM Systems (NYSE:EPAM), jejíž centrála se nachází v USA. Společnost byla založená v roce 1993 a od té doby prošla velkým vývojem a stále roste.

Obrázek ke článku České Radiokomunikace opět hledají nejlepší nápady pro internet věcí

České Radiokomunikace opět hledají nejlepší nápady pro internet věcí

České Radiokomunikace (CRA) pořádají druhý ročník CRA IoT Hackathonů. Zájemci z řad vývojářů a fanoušků moderních technologií mohou změřit své síly a během jediného dne sestrojit co nejzajímavější funkční prototyp zařízení, které bude komunikovat prostřednictvím sítě LoRa. CRA IoT Hackathony se letos uskuteční ve dvou fázích, na jaře a na podzim, v různých městech České republiky. Jarní běh se odstartuje 31. března v Brně a 7. dubna v Praze.

Obrázek ke článku Cloud computing je využíván stále intenzivněji

Cloud computing je využíván stále intenzivněji

Využívání cloud computingu nabývá na intenzitě. Jen v letošním roce vzroste podle analytiků trh se službami veřejného cloudu o 18 %, přičemž o téměř 37 % vzrostou služby typu IaaS. Růst o více než pětinu pak čeká služby poskytování softwaru formou služby, tedy SaaS. Aktuálním trendům v oblasti využívání cloudu se bude věnovat konference Cloud computing v praxi, která se koná 23. března. 2017 v pražském Kongresovém centru Vavruška na Karlově náměstí 5.

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ý