01110111010110 11110101010101 00101011010011 01010111010101 01001010101010 10101010101010 Uuden äärellä rinnakkaisuus ja samanaikaisuus Petteri Kaski Tietotekniikan laitos Aalto-yliopisto ICS-A1120 Ohjelmointi 2 20. huhtikuuta 2016 10101011110101 01010101011101 01010111010110 10101101010110 10101110101010 11101010101101 01110111010110 10111011010101 11110101010101 00010101010101 01011010101110
What s in your hands, I think and hope, is intelligence: the ability to see the machine as more than when you were first led up to it, that you can make it more. Alan J. Perlis (1 April 1922 7 February 1990) in foreword to Harold Abelson and Gerald Jay Sussman, with Julie Sussman, Structure and Interpretation of Computer Programs, 2nd ed., MIT Press, 1996
Sisältö (kierrokset ja moduulit) I 1. Lämmittelykierros Tietokoneen mysteeri 2. Bitit ja data 3. Kombinaatiologiikka 4. Sekventiaalilogiikka 5. Ohjelmoitava kone II Abstraktiot ja analyysi 6. 7. 8. 9. III Funktionaalinen ohjelmointityyli Suorituskykyanalyysi Rekursio Algoritmit ja informaation esitykset Uuden äärellä 10. Rinnakkaisuus ja samanaikaisuus 11. Virtualisointi ja skaalautuvuus 12. Ohjelmoitava vai oppiva kone? (Intel Xeon Phi Knights Landing -lastu, 72 suoritusydintä, 8 miljardia transistoria, 14 nanometrin litografia) (Google Hamina)
Uuden äärellä 10. Samanaikaisuus ja rinnakkaisuus 11. Virtualisointi ja skaalautuvuus 12. Ohjelmoitava vai oppiva kone? helppoa rinnakkaisuutta: rinnakkaiskokoelmat, futuurit ja lupaukset laskentaa saa kuin sähköä seinästä skaalautuvuus omasta koneesta tehdashallitietokoneeseen*; Apache Spark (asennettu Maarille) konetta voi joskus opettaa sen sijaan että sitä ohjelmoidaan, ts. kone osaa joskus näppärästi yleistää sille esitetyistä esimerkeistä *) vain sähkösopimus (ja luottokortti) tarvitaan
The complexity for minimum component costs has increased at a rate of roughly a factor of two per year. Certainly over the short term this rate can be expected to continue, if not to increase. Over the longer term, the rate of increase is a bit more uncertain, although there is no reason to believe it will not remain nearly constant for at least 10 years. Gordon E. Moore, in Electronics (19 April 1965) http://en.wikipedia.org/wiki/moore's_law
http://spectrum.ieee.org/static/special-report-50-years-of-moores-law
The end of dramatic exponential growth in single-processor performance marks the end of the dominance of the single microprocessor in computing. The era of sequential computing must give way to a new era in which parallelism is at the forefront. The Future of Computing Performance: Game Over or Next Level? Samuel H. Fuller and Lynette I. Millett, Eds.; Committee on Sustaining Growth in Computing Performance; National Research Council, The National Academies Press, 2011 10. Samanaikaisuus ja rinnakkaisuus
Intel Haswell (***) 22 nm Haswell AVX2 suoritusydin: 2 x 8 = 16 liukulukulaskentayksikköä (binary32) Intel Xeon E5-2690 v3 12 x AVX2 suoritusydintä = 192 liukulukulaskentayksikköä (2.6 GHz base, 3.5 GHz boost) [1.0 Tflops base, 1.3 Tflops boost] http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf
NVIDIA Kepler (***) SMX: 6 x 32 = 192 liukulukulaskentayksikköä (binary32) Tesla K40 Kepler GK110 (15 SMX) = 2880 liukulukulaskentayksikköä (745 MHz base, 875 MHz boost) [4.3 Tflops base, 5.0 Tflops boost] Tesla K80 2 x Kepler GK210 (13 SMX) = 2 x 2496 = 4992 liukulukulaskentayks. (562 MHz base, 875 MHz boost) [5.6 Tflops base, 8.7 Tflops boost] 28 nm http://international.download.nvidia.com/pdf/kepler/nvidia-kepler-gk110-gk210-architecture-whitepaper.pdf
10. Samanaikaisuus ja rinnakkaisuus
Peräkkäismalli Tähän asti kurssilla olemme rajoittuneet tarkastelemaan laskentaa yksinkertaistettuna ilmiönä jossa ei ole samanaikaisuutta eikä rinnakkaisuutta (~ [yksi] prosessori[ydin] suorittaa konekielikäskyjä yksi kerrallaan, peräkkäin, eristettynä muusta maailmasta)
Laskenta todellisuudessa Peräkkäisyys on sangen karkea yksinkertaistus vallitsevasta todellisuudesta Laskenta on käytännössä samanaikaisesti ja rinnakkain etenevä ilmiö, yli mittakaavojen yksittäisen prosessorin suoritusytimistä tehdashallitietokoneisiin ja tietoverkkoihin (~ kaikki Internetiin kytketyt tietokoneet)
Samanaikaisuus ja rinnakkaisuus ohjelmoijan arjessa? Rinnakkaisnopeutus. Eräät tehtävät ovat luonteeltaan rinnakkaistuvia, ts. koko tehtävä, tai eräät tehtävän osat voidaan pilkkoa toisistaan riippumattomiin alitehtäviin Riippumattomat alitehtävät voidaan suorittaa rinnakkain siten, että koko tehtävä valmistuu ( seinäkelloajassa ) nopeammin kuin peräkkäin suoritettuna Valkopyykki ja väripyykki, kaksi pesukonetta
Samanaikaisuus ja rinnakkaisuus ohjelmoijan arjessa? Kokonaissuorituskyky. Monet yksittäiset tehtävät/palvelupyynnöt eivät rinnakkaistu, koska niiden suoritusaskelten välillä on riippuvuuksia (edellisen askelen tulos on oltava käytettävissä jotta seuraava voidaan suorittaa) Riippuvuuksista huolimatta rinnakkaisuudella voidaan usein parantaa kokonaissuorituskykyä (ratkaistuja tehtäviä tai palvelupyyntöjä aikayksikköä kohti), olettaen että tehtävät/pyynnöt ovat toisistaan riippumattomia Viisi pesulaa pesee viisinkertaisen määrän paitoja, vaikka mikään yksittäinen paita (esipesu, pesu, linkous, silitys) ei sen nopeammin tule pestyksi
Samanaikaisuus ja rinnakkaisuus ohjelmoijan arjessa? Saatavuus/vasteaika. Rinnakkaisuus mahdollistaa alitehtävien jakamisen ja aikatauluttamisen siten, että järjestelmän eri osat ovat saatavilla halutulla tavalla Pyykin vastaanotto/pestyjen luovutus toimii välittömästi riippumatta siitä mitä varsinaisella pesulinjalla tapahtuu
Samanaikaisuus ja rinnakkaisuus ohjelmoijan arjessa? Käytännössä laskenta on ilmiö, jossa useat samanaikaiset suoritukset etenevät rinnakkain, mutta vuorovaikutuksessa Mitä vähemmän vuorovaikutusta, sitä helpompaa on hyödyntää rinnakkaisuutta
10. Samanaikaisuus ja helppo rinnakkaisuus Säikeet ja rinnakkaisuus Asynkroninen suoritus, synkronointi Riippuvuus ja riippumattomuus suorituksessa...... yksinkertaisessa funktionaalisessa suoritusmallissa riippuvuuksien DAG-mallinnus Nopeutuskerroin ja Amdahlin laki Helppo rinnakkaisuus ohjelmoinnissa: Rinnakkaiskokoelmat Futuurit ja lupaukset
Suoritussäie (thread of execution) Ohjelmassa käytössä vain yksi suoritussäie (kuten kurssilla tähän asti) = peräkkäisohjelma
Monisäikeinen ohjelma
Monisäikeinen ohjelma
Monisäikeinen ohjelma Jokaisella säikeellä on oma sisäinen tila (ohjelmalaskuri, muut rekisterit, välimuisti,...) Lisäksi säikeillä on jaettu tila (ohjelman keskusmuistialue, käyttöjärjestelmäresurssit,...) Jokaisella säikeellä on oma näkymä jaettuun tilaan näkymä riippuu säikeen sisäisestä tilasta (esimerkiksi säikeen oman välimuistin sisällöstä!) ja säikeiden vuorovaikutuksesta
Asynkronisuus ja synkronointi Kunkin säikeen suoritus etenee asynkronisesti ja omassa näkymässään, oleellisesti täysin riippumatta mitä muut säikeet tekevät, ellei ohjelmoija erikseen synkronoi säikeiden suoritusta
Vaikea rinnakkaisuus käsittelee säikeitä manuaalisesti erikseen synkronoi säikeitä keskenään yrittää välttää synkronointia käymällä läpi kaikki tavat miten säikeet voivat vuorovaikuttaa keskenään ja synkronoimalla säikeiden toimintaa mahdollisimman vähän siten, että haluttu säikeiden yhteistoiminta saadaan kuitenkin aikaan vaikeaa
Helppo rinnakkaisuus käyttää korkean tason abstraktioita (esimerkiksi rinnakkaiskokoelmat, futuurit ja lupaukset) ohjelmoija ei ota kantaa säikeistykseen eikä synkronointiin ohjelmoija kertoo mitä saa rinnakkaistaa, mutta ei kerro miten rinnakkaistetaan ohjelmoijan vastuulla on edelleen ymmärtää, että korkean tason abstraktiot pohjautuvat säikeisiin ja synkronointiin jaetusta tilasta ja säikeiden omista näkymistä ei tule olettaa mitään mitä abstraktio ei lupaa taata
[Lyhyesti vaikeasta rinnakkaisuudesta ]
Säikeet ja asynkronisuus Scalalla class SumWorker(name: String, target: Int, report: Int) extends Runnable { def run() { // This method contains the code we want to run in a thread //... say, we want to take the sum of the integers i = 1,2,...,target, // and issue a progress report to the console after every // "report" integers var s = 0L var i = 1 while(i <= target) { s = s + i if(i % report == 0) { println("worker %s reporting at i = %d".format(name, i)) } i = i + 1 } println("worker %s is done and reports sum s = %d".format(name, s)) } } // The thread stops when run() returns, i.e. here
Valmistellaan kolme työtä ja kolme säeittä ajamaan töitä... val wa = new SumWorker("SumA", 100000000, 10000000) // prepare worker A val wb = new SumWorker("SumB", 100000000, 10000000) // prepare worker B val wc = new SumWorker("SumC", 100000000, 10000000) // prepare worker C val ta = new Thread(wa) val tb = new Thread(wb) val tc = new Thread(wc) // prepare a thread for worker A // prepare a thread for worker B // prepare a thread for worker C... ja käynnistetään säikeet ta.start() tb.start() tc.start() // start thread of worker A // start thread of worker B // start thread of worker C
Säikeet töissä, asynkronisesti... [demo]
Asynkroninen suoritus vieläkin selkeämmin... class Greeter(id: Int, num: Int) extends Runnable { def run() { for(i <- 0 until num) { print("%d".format(id)) // greet by writing a single digit to console } } } val n = 10 // ten greeters -- one for each digit 0,1,...,9 val num_greetings = 200 // each greeter sends 200 greetings val greeters = (0 until n).map(id => new Greeter(id, num_greetings)) val threads = greeters.map(new Thread(_)) threads.foreach(_.start()) [demo]
Asynkronisuus ja synkronointi Kunkin säikeen suoritus etenee asynkronisesti ja omassa näkymässään, oleellisesti täysin riippumatta mitä muut säikeet tekevät, ellei ohjelmoija erikseen synkronoi säikeiden suoritusta
Kaksi esimerkkiä synkronoinnista Säikeen käynnistäminen käynnistävän ja käynnistyvän t.start() säikeen näkymä jaettuun tilaan on sama, käynnistymishetkellä Säikeen pysähtymisen odottaminen ( säikeeseen liittyminen, join ) t.join() pysähtyneen säikeen jaettuun tilaan tekemät muutokset näkyvät sitä odottaneen säikeen näkymässä
Ohjelmoijan vastuu odottelusta Ohjelmoijan vastuulla on huolehtia, että odottaminen päättyy (Ei ole mitenkään vaikeaa epähuomiossa saada kahta säiettä odottamaan toistensa touhuja ristiin!)
Ohjelmoijan vastuu säikeiden näkymistä jaettuun tilaan
[Lyhyesti vaikeasta rinnakkaisuudesta ] Samanaikaisuuden ja rinnakkaisuuden hallinta on kokeneellekin ohjelmoijalle vaikea asia Varovaisuus on siis paikallaan, ja lisäoppi on suotavaa, mutta kauhusta ei pidä kangistua
Helppo rinnakkaisuus
Rinnakkaiskokoelmat http://docs.scala-lang.org/overviews/parallel-collections/overview.html Lisää vain.par kokoelmatyypin perään tämän jälkeen kaikki kokoelmalle tehtävä laskenta suoritetaan automaattisesti rinnakkain [demo: matriisikertolasku rinnakkain, isoille matriiseille] (Huom: Lisäämällä.par otat ohjelmoijana vastuun, että kutakin kokoelman alkiota käsittelevä laskenta kaikkine sivuvaikutuksineen on riippumatonta muita kokoelman alkioita käsittelevästä laskennasta)
Mitä voidaan rinnakkaistaa?
Funktionaalinen, yksinkertaistettu suoritusmalli Laskenta on jono arvoja, jotka saadaan soveltamalla puhtaita funktioita jonon edeltäviin arvoihin
Riippumattomuus
... koska arvot ovat toisistaan riippumattomia, laskenta voidaan rinnakkaistaa...
Esimerkki nk. SIMD-rinnakkaisuudesta ( Single Instruction, Multiple Data )
Riippuvuus
Mitä voidaan rinnakkaistaa? Riippumaton voidaan rinnakkaistaa, riippuvaista ei voida
Riippuvuuksien kartoittaminen (yksinkertaistetussa funktionaalisessa mallissa)
Riippuvuudet suunnattuna asyklisenä graafina ( DAG ) Oikealla oleva graafi esittää samaa laskentaa (funktioiden parametrien järjestystä vaille)
Sama graafi, oikealla piirrettynä yksi topologinen taso kerrallaan
Idea: Suoritetaan laskenta ahneesti ( opportunistisesti ), ts. jokaisen funktion laskenta aloitetaan heti ja riippumatta muusta käynnissä olevasta laskennasta (*) kun funktiolle annettavat arvot ovat käytettävissä *) mikäli käytännössä rinnakkaislaskentaresurssit vain riittävät!
Liitetään jokaiseen funktiokutsuun 3 2 4 sen suoritusaika Havainto (*): 1 1 5 Ahneella suorituksella 5 1 kokonaislaskenta-aika on laskentagraafin ajaltaan pisimmän suunnatun polun ( kriittisen polun **) vaatima laskenta-aika *) rajattomilla rinnakkaisresursseilla ja vailla viiveitä säikeitä käynnistettäessä, liitettäessä jne **) joita voi olla useita
Futuurit ja lupaukset http://docs.scala-lang.org/overviews/core/futures.html Futuuri ( Future ) (olio, joka edustaa arvoa tai virhettä tulevaisuudessa kun futuuriin liittyvä laskenta valmistuu) Futuureilla on mahdollista laskea ennakkoon (vrt. ennen kuin arvot valmistuvat, on jo kerrottu mitä niille tehdään ) Lupaus ( Promise ) lupausabstraktio ( erikseen täydennettävä futuuri )
Futuurit ja lupaukset [demo]
Helppo rinnakkaisuus http://docs.scala-lang.org/overviews/parallel-collections/overview.html http://docs.scala-lang.org/overviews/core/futures.html
Tehtävät parallel matriisikertolaskun rinnakkaistaminen rinnakkaiskokoelmilla (lisää vain.par ja johan nopeutuu, isoille matriiseille) futures futuuriabstraktio ( arvo tai virhe tulevaisuudessa kun asynkroninen suoritus valmistuu) futuureilla laskenta ennakkoon (vrt. ennen kuin arvot valmistuvat on jo kerrottu mitä niille tehdään ) mekaaninen funktioiden nostaminen tulevaisuuteen ( future-lifting / futurization ) ja tästä saatava tehokkuusetu promises lupausabstraktio ( erikseen täydennettävä futuuri ) työskentely futuureilla ja lupauksilla, lupausten täydentäminen futuureilla threads (haastetehtävä) säikeiden kanssa työskentelyä
Rinnakkaisnopeutuskerroin ja Amdahlin laki suoritusaika peräkkäissuorituksena suoritusaika rinnakkaisuutta hyväksikäyttäen
Amdahlin laki Peräkkäissuorituksen osuus muuten täysin rinnakkaistuvasta ongelmasta = 1 P, missä 0 P < 1 Rinnakkaisnopeutuskerroin on enintään 1/(1 P) http://en.wikipedia.org/wiki/amdahl's_law