Parallelitet i Java

Tags:    programmering

Hej alle sammen.
Er der nogen der kan forklare til mig hvad er Parallelitet i Java, og hvornår man bruger med eventuelt eksempel.
På forhånd tak



3 svar postet i denne tråd vises herunder
1 indlæg har modtaget i alt 23 karma
Sorter efter stemmer Sorter efter dato
Samtidighed (engelsk concurrency) er når noget sker samtidigt. Parallitet er når noget sker på samme tid. For at man kan have parallelitet er man nødt til at have flere beregningsenheder, altså processorer. Parallelitet går ud på at udnytte den kraft.

Lad os sige du vil lægge en masse tal i en array sammen. Du kan lave en løkke som går gennem alle tallene og lægger dem sammen. Men hvis du har 8 kerner i din computer udnytter du kun en af dem.

Fold kodeboks ind/udJava kode 


Spørgsmålet er så, i stedet for at én kerne beregner alt, kan vi bruge de 7 andre kerner til det også? I dette tilfælde og andre er svaret ja, men det er ikke altid tilfældet. Specielt dette eksempel er nemt at parallelisere. Vi tager en liste af tal og beregner en sum. Hvis vi nu delte arbejdet op i 8 dele, får vi 8 mindre lister. Hver kerne kan beregne summen af en af listerne. Til sidst står vi tilbage med 8 summer, for at få den endelige sum skal de 8 tal bare lægges sammen.

Så i stedet for at gøre dette

Fold kodeboks ind/udKode 


Gør vi dette:

Fold kodeboks ind/udKode 


Også til sidst lægges de 8 summer sammen.

Fold kodeboks ind/udKode 


På den måde skal hver kerne kun lægge 1000 tal sammen, i stedet for at en enkelt lægger alle 8000 tal sammen.

Dette er den basale tilgang. Der er nogle ting som ikke er så gode ved denne løsning dog. F.eks. er den lavet specifik til 8 kerner. Så hvis man kører den hos en med 16 kerner udnytter man ikke alt computerkraften. På den kører man den på en computer med kun én kerne vil det køre lidt langsommere fordi processen skal skifte mellem 8 tråde, og det ville være bedre hvis der bare var en enkelt tråd. En sidste ting er at selv med den rigtige antal tråde kan det være en tråd er færdig hurtigere end de andre og så laver ingenting mens de andre arbejder, hvilket også er spild.

Nu spørger du bestemt om Java. En måde er manuelt at oprette tråde og fordele arbejdet ud blandt dem. Men dette er en ret primitiv måde at gøre tingene på. Over tiden er der kommet framework til for at gøre arbejdet nemmere. En populær tilgang, som nu er med i Java 7, som også håndterer ovenstående problemer, er Fork-Join tilgangen.

Fork betyder at man deler en opgave i mindre bidder. F.eks. i stedet for løse SUM(8000 tal), kan man dele det op i 2 x SUM(4000 tal) - (eller 8 x SUM(1000 tal) som vidst før ). Læg mærke til at du kan gentage denne opdeling, f.eks. kan man yderlige opdele SUM(4000 tal) til 2 x SUM(2000 tal).

Join betyder at man samler delresultaterne. I dette tilfælde vil det være at lægge summerne sammen. Andre problemer kunne være at man havde en lang tekst og ville tælle antallet af punktummer. Fork (opdel) teksten i to dele, og find hvor mange punktummer der i hver del. Join dem ved at lægge hvor mange punktummer der var i hver del sammen.



Jeg har fundet et eksempel fra http://homes.cs.washington.edu/~djg/teachingMaterials/grossmanSPAC_forkJoinFramework.html , vidst nedenunder som lige præcis lægger tal sammen via. Java's fork join framework.

En opgave er Sum som her er arver fra en RecursiveTask som beregner en long, altså et tal. RecursiveTask er fra Fork/join frameworket. Der sættes en bagetelgrænse på 5000 tal, dvs. når der er færre end 5000 tal i en delopgave gider vi ikke at splitte mere. Den bruges i linje 22 som siger at hvis vi har under 5000 tal i denne opgave så bare beregn resultatet.

Det mere interessante er hvis der stadig er mere end 5000 tal. Så opdeles problemet i to dele på linje 28-30. Den venstre del bliver forket, som en helt ny opgave, og ellers fortsættes der med at beregne den højre del. Efter den højre del er færdig med summen, er vi nødt til at vente på den venstre del er også er færdig. Når den er det kan de to tal lægges sammen som resultatet.

Fold kodeboks ind/udJava kode 


Det Fork-Join frameworket så gør er automatisk at tildele opgaver til kerner. Læg mærke til vi kan sagtens lave flere "opgaver" end der er kerner. Så en kerne kan få flere opgaver at løse. På den måde kan vi altid udnytte den computerkraft der er tilgængelig, selv hvis det kun er en 1 kerne. Hvis en kerne bliver færdig med alle sine opgaver før de andre, er der yderlige en feature kaldet "works stealing". Det indebærer at den færdige kerne stjæler noget arbejde fra en anden kerne og begynder på det. Det undgår problemet nævnt tidligere med at man står med en kerne der ikke laver noget.



Indlæg senest redigeret d. 06.12.2015 19:42 af Bruger #14645
Takkker :)



Super seriøst svar Søren. Respekt!



t