Jak v praxi používáte paralelizmus rubrika: Programování: Jiné

9 Taco
položil/-a 30.12.2015

Dnes už máme hodně jazyků, které umožňují paralelizmus by jazyk. Některé si ještě pomáhají syntaxí, některé to řeší rozdělením na mutable/imutable kód a funkcionálnem.

Teorie je známá, ale jak to funguje a jak to používáte v praxi? Musíte tomu kódu nějak pomáhat, nebo si je schopen engine/compilátor sám určit, na kolika jádrech to má, a co zparalelizuje a co ne.

odkaz
9 Petr Voneš
odpověděl/-a 2.1.2016
 
upravil/-a 2.1.2016

Neznam sice Haskel, ale prijde mi z tech odpovedi, ze tu paralelizaci prilis zjednodusujete. Predstava ze neco samo spravne paralelizuje jakykoli kod je usmevna :-) K tomu me napada otazka, jak merite skutecny prinos takove paralelizace ? To ze neco pustim ve sto threadech jeste neznamena, ze se celkovy vykon zlepsil. Treba jen sekvencni cteni z disku muze byt nakonec lepsi, nez nahodne paralelni cteni.

Typicky lze ulohy rozdelit na CPU a I/O. U obou ma paralelizace smysl, ovsem neni rozhodne snadna. Stejne tak je v praxi velmi casty pripad uloha, ktera pracuje se sdilenymi daty.

U CPU operaci zalezi na konkretnim hardware (CPU architekture) kde takova uloha bezi. Protoze skutecny vykon ovlivnuje zaprve minimalizace blokovani jednotlivych threadu a cteni/zapis dat do sdilene pameti, kde v pripade dnes uz beznych vicejadrovych procesoru hraje znacnou roli jev zvany false sharing a tady vam asi zadna automatika moc nepomuze :-) Naprosto bezne je i prehazovani poradi provadeni instrukci procesorem, ktere dnes provadi vsechny architektury, IA konzervativneji, ARM vice agresivne. Toto vse je treba zohlednit pokud ma mit paralelizace skutecny prinos.

U I/O operaci je nutna podpora celeho prostredi (ne jen jazyka) kde aplikace bezi pro asynchronni zpracovani. Typicky pripad je treba zpracovani HTTP requestu na serveru. Pokud by se ve zpracovani reqestu kde se napriklad cte soubor z disku postupovalo klasicky synchronne, moc velka slava to nebude. Zde ma paralelizace zpracovani pomoci asynchronniho volani dlouhotrvajicich I/O operaci vyznam, protoze dokaze vratit thread zpracovavajici request zpet do hry, po dobu trvani I/O operace. Jak ve Windows API tak v .NET je pro toto jiz leta podpora, budto APM patternem nebo noveji jazykovymi konstrukcemi async/await coz je ale stale jen omacka kolem tehoz. Stale je treba vedet kdy neco takoveho pouzit, aby to davalo smysl a bylo prinosem. I kdyz Asynchronous Everything ;-)

Komentáře

  • Honza Břešťan : "Predstava ze neco samo spravne paralelizuje jakykoli kod je usmevna" a dnesni CPU delaji na urovni instrukci co? Dokonce nejenom s "vypocetni" praci, ale i s pristupem do pameti, coz je z pohledu CPU dlouhotrvajici IO operace. S paralelismem je to jako se vsim - da se to delat rucne, ale pokud jsou vyssi vrstvy rozumne navrzene, prijatelne (povolene ztraty na vykonu oproti rucne vyladenemu kodu) to jde i automaticky. Za par let tohle muze byt stejne usmevna debata jako drivejsi diskuse o managed pameti, jak to je pomale a k nicemu. Konkretne k Haskellu je potreba rict par veci: Predevsim to jeho kompilator vubec nedela by default, je na to potreba experimentalni extenze (napr. Data Parallel Haskell). Mnohem castejsi je explicitni paralelismus, podobne jako treba u PLINQu, nebo paralelismus na vyssi urovni (cele procesy). Na druhou stranu ma atomaticky paralelismus v Haskellu mnohem vetsi sanci na realny uspech nez u soucasnych .NET jazyku, protoze data jsou vzdy immutable, samotny jazyk je brutalne lazy a veskera interakce s okolnim svetem je explicitne zabalena do IO monady urcujici poradi operaci, coz dava prostor korektnimu spekulativnimu a paralelnimu vyhodnocovani argumentu (jako kdyby v C# vsechno bylo automaticky Lazy<T> a runtime se mohl sam rozhodnout, kdy to vyhodnotit, pricemz az na vyjimecne situace nemel moznost jakkoliv "rozbit" korektnost programu vzhledem k side effectum). 2.1.2016
  • Petr Voneš : Prave ze s tim pristupem do pameti jim to stale moc nejde. Ty ruzne spekulativni dopredne analyzy instrukci uz nemaji s paralelizaci mnoho spolecneho. Revolucni myslenka cele tohle zahodit a nechat to jen na "certifikovanem" prekladaci primo do CPU mikrokodu se ovsem nakonec neujala (Itanium). Predstava ze vsechna data jsou jen immutable je pro mne ovsem ponekud omezena. 2.1.2016
  • Honza Břešťan : Porad to jde o dost lip, nez kdyby zadne paralelni pipeliny a spekulativni prace s pameti neexistovaly ani na jedne urovni, vsechny instrukce se vykonavaly sekvencne a vsechny pristupy do pameti synchronne. Pro obecny a "naslepo" napsany program to samozrejme zdaleka nedosahuje plneho potencialu, ale tady treba muze application-level paralelismus pomoct. Kdyz se flaka CPU backend, da se vyuzit hyper-threading, akorat musi nekdo (v tomhle pripade kompilator nebo runtime aplikace) urcit, co se teda ma na tehle urovni paralelizovat. V Haskellu jsou podle me nejzhavejsimi kandidaty prave thunky - lazy hodnoty cekajici na (potencionalne CPU narocne) castecne vyhodnoceni, u ktereho vime (protoze Haskell), ze nezpusobi side effect. Samozrejme ani jedno se na jednom stroji skoro nikdy nevyrovna rucne napsanemu a odladenemu single-thread kodu, ale to vyzaduje hodne dobrou znalost vsech vrstev. Treba http://funkcionalne.cz/ se timhle tematem zaobira docela casto. 2.1.2016
  • Honza Břešťan : Co se tyce immutable dat, tak to je samozrejme pro programatora velike omezeni (resp. vyzaduje to velky myslenkovy posun), pokud je zvykly menit sdileny stav, ale teoreticky je to ekvivalentni (menena hodnota == stream hodnot v case, iterace s mutaci == fold, ...) a technicky to zase tak problematicke neni, protoze to umoznuje pouzivat treba persistent data structures a hlavne to zajistuje izolaci, ktera pak umozni snadneji program paralelizovat (at uz implicitne nebo explicitne). 2.1.2016
  • Taco : @Petr Voneš: Nechci se tě dotknout, ale hned ta první slova "Neznam sice Haskel" mi připoměla velice šťavnatou diskusi, kde se jakýsi gamer do krve hádal, že FP nemůže vůbec fungovat, přestože ho teda moc nezná a nic o tom neví :-) * Možná jsem moc velkej idealista, ale tak nějak si představuji, že když si fakt zkušený machr z oboru sedne, a definuje si všechny možné scénáře, na kterých může v paralelizmu narazit, a pak z toho udělá nějaký deklarativní jazyk - tak to bude furt lepší, než když to mi, obyčejní dělňasové budem dělat explicitně zas a znova, a v mnoha případech blbě. Prostě klasika, proč psát v ASM, když můžu psát v C. 2.1.2016
  • Petr Voneš : @Taco: Vzdyt ono to postupne vyleza, ze to ma radu omezeni, ktera jsem nebral v uvahu. 2.1.2016
  • Petr Voneš : @JB: Coz stale vypada ze to problem jen odsouva jinam. Nakonec v nejakem miste stejne musim mit tu cast kodu, ktera paralelne vybira napriklad zpravy z jedne fronty nebo zapisuje do jedne tabulky a podobne. Za skutecnou podporu paralelizace bych povazoval napriklad neco, co samo vyresi onen false sharing. 2.1.2016
  • harrison314 : @Taco: aj mne sa zda ze to neuveritelne idelaizujes, aj Haskell, aj moznosti paraleizacie uloh. 3.1.2016
  • IAmAwesome24_7 : Mám komentář k tomu false sharingu - s ním není až tak těžké bojovat (v C/C++ a pokud paměti není příliš málo) - stačí mít položky stejně velké jako cacheline (= vyplnit je na velikost cacheline) a žádat o ně zarovnaně. Myslím, že spíš narážíte na to, že pokud jedno vlákno zapíše data do paměti, tak jiné vlákno na jiném procesoru musí data přečíst až z paměti, nikoliv z cache, což trvá mnohem déle. Stejně tak dlouho trvá každé zamčení/odemčení mutexu, což vede některé k používání lock-free struktur. Proč jen některé? Je důležité prvně měřit, a až pak optimalizovat - a pokud zrovna mutexy nejsou největší zátěž, tak proč je optimalizovat :-) 3.1.2016
  • Petr Voneš : Problem jsou ale pole tech polozek, protoze zarovnanim se to uz zvetsi. Dale efektivni pristup k datum ve vicerozmernych polich (jestli ma byt prvni radek/sloupec) atd. Bez mereni se to uplne odhadnout neda. Lock-free synchronizacni prvky jsou takrka nutnost (a nastesti jsou v knihovnach uz implementovane), protoze prechody mezi user-kernel modem (Windows) i za pouziti triku se spin countem jsou moc drahe. Navic je zabavne je zkoumat, pripadne si je zkusit i napsat (bez chyby). Pokud neco tvrdi ze automaticky podporuje paralelizaci jakehokoli kodu tak bych cekal, ze automaticky resi tyto problemy :-) 3.1.2016
  • Taco : @harrison314: ad mé idealizování: V tom není problém. Jsem to na mnoha místech přiznával, že mám k Haskellu až nezdravou důvěru. Bezpochyby mnoho mých představ o něm bude značně nepřesných. * Já mám zase dojem, že tu máme další vymírání názorů, a že bude muset ještě odtéct hodně vody, než se lidé paralelizmu přestanou bát a nebudou ho už brát jako obrovskej problém - podobně jako správu paměti. * Můj názor: Máš-li všechny výrazy immutable, tak máš jen jednu kritickou sekci, kde musíš řešit synchronizaci. (Přesněji, máš tolik kritických sekcí, kolik máš mutable výrazů +1) Všechen ostatní kód, a může být libovolně rozsáhlý, se dá automaticky a snadno paralelizovat. (Zda to zvládá Haskell a jak dobře, v tom se určitě mohu plést.) 3.1.2016
  • Kit : @Taco: Všechny výrazy dělám immutable - kromě řídicích proměnných v cyklu. Právě cykly se blbě paralelizují. 3.1.2016
  • harrison314 : @Taco: mal som predmet co sa venoval parlnemu programovaniu, principom a mechnizmom. Plus mam s tym aj skunosti v C,C# (TPL, PLINQ) a aj trochu v Haskelly. Viem (zo skusnosti + skola) na ake ulohy sa paralelizacia hodi a na ake nie. Tiez mi diskusia okolo toho pride bezprecedentna. Takze az mas ulohu, kde sa to hodi, tak smelo do toho. A nepytaj si "povolenie" na fore. Rad si dokonca aj pozriem kody v haskelly (mam ho rad, kvli magickosti a prisnej typovosti). 3.1.2016
  • harrison314 : @Kit: ako ktore... 3.1.2016
  • Kit : @harrison314: Většinu cyklů konvertuji na map/filter/reduce. Měl jsem na mysli ty zbývající... 3.1.2016
  • Honza Břešťan : @Taco: "bude muset ještě odtéct hodně vody, než se lidé paralelizmu přestanou bát" - v tomhle jsou na vine jazyky, protoze i treba v C# s jeho novou asynchronicitou a neskutecne peknou Task Parallel Library zalozenou na komonadach jsem jeste asi nevidel produkcni kod (na vic nez par radku) bez chyb zpusobenych spatnym chapanim memory modelu nebo synchronizacnich prvku (vyjma par OSS projektu od spicek .NET vyvoje). Sam ty chyby samozrejme delam taky, vetsinou se to odchyti treba celodennim code review ve dvou, ale to je celkem draha sranda. Dokud jazyk/platforma dava jen moznosti a ne zaruky, bude to vzdycky problem. Docela zajimave se v tomhle jevi jazyky jako Erlang, Haskell, Rust nebo Go, ktere velkou cast problemu resi svymi omezenimi. Mozna to moc demonizuju, ale mnohem vetsi starost mi delaji programatori, kteri se manualniho paralelismu neboji :) 3.1.2016
  • Taco : @Jan Břešťan: "mnohem vetsi starost mi delaji programatori, kteri se manualniho paralelismu neboji" - tak pod to bych se podepsal. 3.1.2016
  • nov.ondrej : [chvástání]Já se tedy paralelismu vůbec nebojím. Ale možná je to taky tím, že nepoužívám nějaké neznámé a divně fungující knihovny, ale že jsem si veškeré nástroje na paralelizmus (v C++) napsal a poctivě odladil sám a to včetně všelijakých race conditions, deadlocků a podobných věcí, které jsem cestou potkal. Byla to dobrá škola. Dneska pro mě není problém napsat paralel_for v čistém C++ bez podpory OpenMP jen s minimem deklarací navíc kolem a protože vím, jak to všechno uvnitř funguje a to do poslední instrukce, tak tomu i víc věřím. A že to je dost odladěnný, to jsem si jist, všechny aktuálně udržované servery, kam chodí desítky tisíc uživatelů denně a vyrobí stovky tisíc requestů mají zpravidla nulový crashcount (jo, v tom obskurním nebezpečným jazyce bez GC). [/chvástání] 3.1.2016
  • Petr Voneš : @JB: To je ale stale ten problem snadnost vs znalost :-) Pred takovymi patnacti lety, v dobe drevniho unmanaged a "unsafe" kodu, bylo psani multithreadovych aplikaci se spolehlivosti v provozu 24/7 radove komplikovanejsi nez dnes a take se to dalo. Pripada mi ze to cekani na zazrak, ktery programatora zcela odstini od teto problematiky pri zachovani efektivity vysledneho kodu (a bez z meho pohledu absurdnich omezeni zminovanych u tech ostatnich jazyku), je ponekud marne. Neni nakonec jeste drazsi ? Dnes vlastne nikdo nestoji o to, znat veci prilis do detailu. Jenze tehle pristup "vse je/musi byt snadne a blbovzdorne", nejen pro uzivatele ale uz i programatory, nakonec narazi na sve limity. 4.1.2016
  • Taco : @Petr Voneš: "Jenze tehle pristup "vse je/musi byt snadne a blbovzdorne", nejen pro uzivatele ale uz i programatory, nakonec narazi na sve limity." - Jaké? 4.1.2016
  • Petr Voneš : Ze potencial soucasneho hardware nebude dobre vyuzit, protoze je to "slozite". 4.1.2016

Pro zobrazení všech 7 odpovědí se prosím přihlaste:

Rychlé přihlášení přes sociální sítě:

Nebo se přihlaste jménem a heslem:

Zadejte prosím svou e-mailovou adresu.
Zadejte své heslo.