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 464×

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 NEWTON Media prohledá 200  milionů mediálních zpráv během sekund díky Cisco UCS

NEWTON Media prohledá 200 milionů mediálních zpráv během sekund díky Cisco UCS

Česká společnost NEWTON Media provozuje největší archiv mediálních zpráv ve střední a východní Evropě. Mezi její zákazníky patří například ministerstva, evropské instituce nebo komerční firmy z nejrůznějších oborů. NEWTON Media rozesílá svým zákazníkům každý den monitoring médií podle nastavených klíčových slov a nabízí online službu, kde lze vyhledat mediální výstupy v plném znění od roku 1996.

Reklama
Reklama
Obrázek ke článku Delphi 10.1.2 (Berlin Update 2) – na co se můžeme těšit

Delphi 10.1.2 (Berlin Update 2) – na co se můžeme těšit

Touto roční dobou, kdy je zem pokrytá barevným listím a prsty křehnou v mrazivých ránech, se obvykle těšíme na zbrusu novou verzi RAD Studia. Letos si však ale budeme muset počkat na Godzillu a Linux až do jara. Vezměme tedy za vděk alespoň updatem 2 a jelikož dle vyjádření pánů z Embarcadero se budou nové věci objevovat průběžně, pojďme se na to tedy podívat.

Obrázek ke článku Konference: Moderní datová centra pro byznys dneška se koná už 24. 11.

Konference: Moderní datová centra pro byznys dneška se koná už 24. 11.

Stále rostoucí zájem o cloudové služby i maximální důraz na pružnost, spolehlivost a bezpečnost IT vedou k výrazným inovacím v datových centrech. V infrastruktuře datových center hraje stále významnější roli software a stále častěji se lze setkat s hybridními přístupy k jejich budování i provozu.

Obrázek ke článku Konference: Mobilní technologie mají velký potenciál pro byznys

Konference: Mobilní technologie mají velký potenciál pro byznys

Firmy by se podle analytiků společnosti Gartner měly  rychle přizpůsobit skutečnosti, že mobilní technologie už zdaleka nejsou horkou novinkou, ale standardní součástí byznysu. I přesto - nebo možná právě proto - tu nabízejí velký potenciál. Kde tedy jsou ty největší příležitosti? I tomu se bude věnovat již čtvrtý ročník úspěšné konference Mobilní řešení pro business.

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 © 20032016 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý