Parallel Patterns Library(PPL)Tomas Dabašinskas, Microsoft Student Partner
Lygiagretus programavimas sudėtingasPadaromas tik labiau patyrusių programuotojųLygiagretūs šablonai nėra paplitę, gerai žinomi ir lengvai įgyvendinamiKrūva galimų problemų:Gijų varžymaisi (races)Mirties taškas (deadlock)Gyvas taškas (livelock)Pamiršti pranešimai (lost event notifications)…
Ko nori programuotojai?
Visual Studio 2010
Parallel Patterns Library (PPL)Veikia kaip ConcurrencyRuntimekomponentasAbstrakcijos lygis tarp programos ir gijų mechanizmoLengvas panaudojimasGalimybė plėstis (scalability)
Struktūrinis ir nestruktūrinis lygiagretumasStruktūrinis:Lygiagretus kodas pradedamas ir baigiamas viename konteksteUžduotis negali baigtis, kol nesibaigia jos dukterinės užduotysDidesnis našumasNestruktūrinis:Leidžia užduotį pradėti ir baigti ar jai laukti skirtinguose kontekstuoseLankstesnis
PPL sudėtisLygiagrečios užduotys (Task Parallelism)	Kelios užduotys lygiagrečiaiLygiagretūs algoritmai (Parallel Algorithms)	Bendriniai algoritmai darbui su duomenų rinkiniaisLygiagrečios talpyklos ir objektai (Parallel containers & objects)	Bendrinės talpyklos/objektai saugiam darbui su jų viduje esančiais elementais
PPL: UžduotysUžduotis (Task)–skaičiavimas, kuris viduje gali būti išskaidytastask_handle klasėUžduočių grupė (Task group) – užduočių, formuojančių loginius skaičiavimus, grupėtask_group klasėstructured_task_group klasė
Užduočių tipai
Užduotys. Kada/kur naudoti?Rekursiniuose metoduoseNorint išskaidyti darbą į atskiras dalisNorėdami aprašysi savo lygiagretų algoritmą, kai neužtenka standartinių PPL algoritmų.Jei galime, naudojame pastaruosius
Let’s CODE!AKA DEMO
PPL: AlgoritmaiPPL Algoritmai panašūs į STL algoritmusIšnaudoja jau esamą ConcurrencyRuntimefunkctionalumąAlgoritmai:parallel_forparallel_for(begin,end,step,[](inti){ …});parallel_for_eachparallel_for(v.begin(),v.end(),[](inti){ … });parallel_invokeparallel_invoke([]{…},[]{…},[]{…},…,[]{…});
parallel_for()Kartoja tą pačią užduotį lygiagrečiaiOptimaliai išskaido užduotis lygiagrečiam vykdymuiBalansuoja tarp išskaidytų dalių priklausomai nuo apkrovų.Užduočių vykdymas neturi numatytos tvarkosArgumentai:Pradinė reikšmė, galinė reikšmė, žingsnis, funkcijaPradinė reikšmė, galinė reikšmė, funkcija	(Žingsnis tokiu atveju pagal nutylėjimą = 1)
for()  parallel_for()Daugelį for ciklų galima pakeisti parallel_for, tačiau:Ciklo indeksas (_Index_type) gali būti tik sveiko tipoIteracija gali vykti tik į priekį (jei žingsnis (_Step) mažesnis nei 1, gauna klaida)Pabaigos sąlyga turi būti konkreti. Iteracija baigiama, kai iteracijos kintamasis pasiekia reikšmę _Last
parallel_for_each()Lygiagrečiai atlieka veiksmus iteruojamoje talpykloje (tarkim tokioje, kokias suteikia STL)Naudoja tą pačią užduočių skaidymo logiką kaip ir parallel_forUžduočių vykdymas taip pat neturi numatytos tvarkosVeikia tiek su einančiais į priekį (forward) iteratoriais, tiek su atsitiktinio priėjimo (randomaccess) iteratoriais. Su pastaraisiais greičiau.
parallel_invoke()Vykdo užduočių rinkinį paraleliai.Nebaigia darbo tol, kol darbo nebaigia visos lygiagrečiai vykdomos užduotysPriima nuo 2 iki 10 parametrų – funkcijų, kurias vykdys. Kiekviena perduodama funkcija neturi turėti parametrų.Užduočių vykdymas taip pat neturi numatytos tvarkosPatogus, kai norima vykdyti keletą nepriklausomų užduočių lygiagrečiai
parallel_invoke() pavyzdysunsignedintcount_primes(intstart,intend){unsignedintcount=0u;for(intn=start;n<end;++n){if(is_prime(n))++count;}returncount;}parallel_invoke([&]{prime_count1=count_primes(0,10000);},[&]{prime_count2=count_primes(10000,20000);},[&]{prime_count3=count_primes(20000,30000);},[&]{prime_count4=count_primes(30000,40000);});
Let’s CODE!AKA DEMO
PPL: Talpyklos ir objektai
concurent_vectorNaudojimas panašus į STL bibliotekos vector klasėsPapildymas, paėmimas, iteracija veikia lygiagrečiaiElementus pridėti galima tik į galą (nėra insert() metodo)Galima pašalinti visus elementus su clear() metodu. Šalinti vieno elemento negalima.Nesaugo savo elementų atmintyje iš eilės, tad negalima atlikti kai kurių masyvam būdingų operacijųGalima keisti dydį su grow_by() ir grow_to_at_least() (atitikmuo resize())
concurent_queueNaudojimas panašus į STL bibliotekos queue() klasėsLeidžia pasiekti pirmą (dequeue) ir paskutinį (enqueue) elementus.Nėra front() ir pop() metodų. Vietoj jų – try_pop()Nėraback() metodo, tad negalima kreiptis į eilės galąMetodu empty() galima patikrinti ar eilė tuščia.Iteracija ir bei dydžio gavimas nėra pritaikyti lygiagrečiam veikimu
combinableSuteikia daug kartų naudojamą saugyklą gijoje, iš kurių rezultatai sujungiami į bendrąNaudingas, kai reikia kažkokiu resursu dalintis keliose gijose/užduotyseNebereikia naudoti papildomų priemonių (tarkim mutex)combinable<int>sum;parallel_for_each(a.begin(),a.end(),[&](inti){sum.local()+=(is_prime(i)?i:0);});prime_sum=sum.combine(plus<int>());
PPL: Lygiagretaus darbo atšaukimas (sustabdymas)tg1t1t2t3tg2UžduotisUžduočių grupėt4t5
Lygiagrečių užduočių stabdymasDu būdai sustabdyti:task_group::cancel() ir structured_task_group::cancel()Atšaukia užduočių grupę ir visas dukterines užduočių grupes (iš viršaus į apačią)EfektyvesnisIšimties (exception) išmetimas užduoties darbo funkcijoje.Atšaukinėja kiekvieną užduočių grupę atskirai (iš apačios į viršų)
Lygiagrečių algoritmų stabdymasKadangi PPL lygiagretūs algoritmai veikia lygiagrečių užduočių pagrindu, jiems sustabdyti (atšaukti) galime naudoti tuos pačios būdus.structured_task_grouptg;task_group_statusstatus=tg.run_and_wait([&]{parallel_for(0,100,[&](inti){// Atšaukiam užduotį, kai pasiekiam 50if(i==50) {tg.cancel();}else{// Normalus darbas}});});
(NE)stabdomLygiagretaus darbo stabdymas (atšaukimas) tinkamas naudoti, kai kiekviena susijusios grupės užduotis darbą gali baigti savo laikuYra atvejų, kai lygiagrečios užduočių grupės sustabdymas nėra geras sprendimas:Užduotis, kuri atblokuoja kitą aktyvią užduotį, nėra startavusi  Ši užduotis nestartuoja, jei grupė atšaukiama  Galimas mirties taškas (deadlock)
Parallel Debugger
Parallel DebuggerParallel TasksParallel Stacks
Let’s CODE!AKA DEMO
Ačiū už dėmesįTomas Dabašinskastomas@studentpartners.comhttp://www.winblog.lt

Parallel Patterns Library (PPL) in Visual C++ 2010

  • 1.
    Parallel Patterns Library(PPL)TomasDabašinskas, Microsoft Student Partner
  • 2.
    Lygiagretus programavimas sudėtingasPadaromastik labiau patyrusių programuotojųLygiagretūs šablonai nėra paplitę, gerai žinomi ir lengvai įgyvendinamiKrūva galimų problemų:Gijų varžymaisi (races)Mirties taškas (deadlock)Gyvas taškas (livelock)Pamiršti pranešimai (lost event notifications)…
  • 3.
  • 4.
  • 5.
    Parallel Patterns Library(PPL)Veikia kaip ConcurrencyRuntimekomponentasAbstrakcijos lygis tarp programos ir gijų mechanizmoLengvas panaudojimasGalimybė plėstis (scalability)
  • 6.
    Struktūrinis ir nestruktūrinislygiagretumasStruktūrinis:Lygiagretus kodas pradedamas ir baigiamas viename konteksteUžduotis negali baigtis, kol nesibaigia jos dukterinės užduotysDidesnis našumasNestruktūrinis:Leidžia užduotį pradėti ir baigti ar jai laukti skirtinguose kontekstuoseLankstesnis
  • 7.
    PPL sudėtisLygiagrečios užduotys(Task Parallelism) Kelios užduotys lygiagrečiaiLygiagretūs algoritmai (Parallel Algorithms) Bendriniai algoritmai darbui su duomenų rinkiniaisLygiagrečios talpyklos ir objektai (Parallel containers & objects) Bendrinės talpyklos/objektai saugiam darbui su jų viduje esančiais elementais
  • 8.
    PPL: UžduotysUžduotis (Task)–skaičiavimas,kuris viduje gali būti išskaidytastask_handle klasėUžduočių grupė (Task group) – užduočių, formuojančių loginius skaičiavimus, grupėtask_group klasėstructured_task_group klasė
  • 9.
  • 10.
    Užduotys. Kada/kur naudoti?RekursiniuosemetoduoseNorint išskaidyti darbą į atskiras dalisNorėdami aprašysi savo lygiagretų algoritmą, kai neužtenka standartinių PPL algoritmų.Jei galime, naudojame pastaruosius
  • 11.
  • 12.
    PPL: AlgoritmaiPPL Algoritmaipanašūs į STL algoritmusIšnaudoja jau esamą ConcurrencyRuntimefunkctionalumąAlgoritmai:parallel_forparallel_for(begin,end,step,[](inti){ …});parallel_for_eachparallel_for(v.begin(),v.end(),[](inti){ … });parallel_invokeparallel_invoke([]{…},[]{…},[]{…},…,[]{…});
  • 13.
    parallel_for()Kartoja tą pačiąužduotį lygiagrečiaiOptimaliai išskaido užduotis lygiagrečiam vykdymuiBalansuoja tarp išskaidytų dalių priklausomai nuo apkrovų.Užduočių vykdymas neturi numatytos tvarkosArgumentai:Pradinė reikšmė, galinė reikšmė, žingsnis, funkcijaPradinė reikšmė, galinė reikšmė, funkcija (Žingsnis tokiu atveju pagal nutylėjimą = 1)
  • 14.
    for()  parallel_for()Daugelįfor ciklų galima pakeisti parallel_for, tačiau:Ciklo indeksas (_Index_type) gali būti tik sveiko tipoIteracija gali vykti tik į priekį (jei žingsnis (_Step) mažesnis nei 1, gauna klaida)Pabaigos sąlyga turi būti konkreti. Iteracija baigiama, kai iteracijos kintamasis pasiekia reikšmę _Last
  • 15.
    parallel_for_each()Lygiagrečiai atlieka veiksmusiteruojamoje talpykloje (tarkim tokioje, kokias suteikia STL)Naudoja tą pačią užduočių skaidymo logiką kaip ir parallel_forUžduočių vykdymas taip pat neturi numatytos tvarkosVeikia tiek su einančiais į priekį (forward) iteratoriais, tiek su atsitiktinio priėjimo (randomaccess) iteratoriais. Su pastaraisiais greičiau.
  • 16.
    parallel_invoke()Vykdo užduočių rinkinįparaleliai.Nebaigia darbo tol, kol darbo nebaigia visos lygiagrečiai vykdomos užduotysPriima nuo 2 iki 10 parametrų – funkcijų, kurias vykdys. Kiekviena perduodama funkcija neturi turėti parametrų.Užduočių vykdymas taip pat neturi numatytos tvarkosPatogus, kai norima vykdyti keletą nepriklausomų užduočių lygiagrečiai
  • 17.
  • 18.
  • 19.
  • 20.
    concurent_vectorNaudojimas panašus įSTL bibliotekos vector klasėsPapildymas, paėmimas, iteracija veikia lygiagrečiaiElementus pridėti galima tik į galą (nėra insert() metodo)Galima pašalinti visus elementus su clear() metodu. Šalinti vieno elemento negalima.Nesaugo savo elementų atmintyje iš eilės, tad negalima atlikti kai kurių masyvam būdingų operacijųGalima keisti dydį su grow_by() ir grow_to_at_least() (atitikmuo resize())
  • 21.
    concurent_queueNaudojimas panašus įSTL bibliotekos queue() klasėsLeidžia pasiekti pirmą (dequeue) ir paskutinį (enqueue) elementus.Nėra front() ir pop() metodų. Vietoj jų – try_pop()Nėraback() metodo, tad negalima kreiptis į eilės galąMetodu empty() galima patikrinti ar eilė tuščia.Iteracija ir bei dydžio gavimas nėra pritaikyti lygiagrečiam veikimu
  • 22.
    combinableSuteikia daug kartųnaudojamą saugyklą gijoje, iš kurių rezultatai sujungiami į bendrąNaudingas, kai reikia kažkokiu resursu dalintis keliose gijose/užduotyseNebereikia naudoti papildomų priemonių (tarkim mutex)combinable<int>sum;parallel_for_each(a.begin(),a.end(),[&](inti){sum.local()+=(is_prime(i)?i:0);});prime_sum=sum.combine(plus<int>());
  • 23.
    PPL: Lygiagretaus darboatšaukimas (sustabdymas)tg1t1t2t3tg2UžduotisUžduočių grupėt4t5
  • 24.
    Lygiagrečių užduočių stabdymasDubūdai sustabdyti:task_group::cancel() ir structured_task_group::cancel()Atšaukia užduočių grupę ir visas dukterines užduočių grupes (iš viršaus į apačią)EfektyvesnisIšimties (exception) išmetimas užduoties darbo funkcijoje.Atšaukinėja kiekvieną užduočių grupę atskirai (iš apačios į viršų)
  • 25.
    Lygiagrečių algoritmų stabdymasKadangiPPL lygiagretūs algoritmai veikia lygiagrečių užduočių pagrindu, jiems sustabdyti (atšaukti) galime naudoti tuos pačios būdus.structured_task_grouptg;task_group_statusstatus=tg.run_and_wait([&]{parallel_for(0,100,[&](inti){// Atšaukiam užduotį, kai pasiekiam 50if(i==50) {tg.cancel();}else{// Normalus darbas}});});
  • 26.
    (NE)stabdomLygiagretaus darbo stabdymas(atšaukimas) tinkamas naudoti, kai kiekviena susijusios grupės užduotis darbą gali baigti savo laikuYra atvejų, kai lygiagrečios užduočių grupės sustabdymas nėra geras sprendimas:Užduotis, kuri atblokuoja kitą aktyvią užduotį, nėra startavusi  Ši užduotis nestartuoja, jei grupė atšaukiama  Galimas mirties taškas (deadlock)
  • 27.
  • 28.
  • 29.
  • 30.
    Ačiū už dėmesįTomasDabašinskastomas@studentpartners.comhttp://www.winblog.lt