Forkjoinpool
ForkJoinPool-luokka Javassa Fork/Join-kehystä varten on juuri tämän toteutus. Se tarjoaa mekanismit tehtävien hallintaan, jotka voidaan jakaa pienempiin osatehtäviin ja suorittaa rinnakkain.
Main.java
1ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinPool perustuu kahteen perustoimintoon: fork ja join. Fork tarkoittaa toimintoa, jossa suuri tehtävä jaetaan useisiin pienempiin osatehtäviin, jotka voidaan suorittaa rinnakkain. Join on prosessi, jossa näiden osatehtävien tulokset yhdistetään alkuperäisen tehtävän tulokseksi.
Tapaustutkimus
Kuvittele, että sinun täytyy analysoida valtava tietoaineisto, joka voidaan jakaa useisiin pienempiin osiin. Jos käsittelet jokaisen tietoaineiston erikseen ja sitten yhdistät tulokset, voit nopeuttaa käsittelyä merkittävästi, erityisesti moniprosessorijärjestelmissä.
ForkJoinPoolin käyttö
On olemassa 2 luokkaa, joilla toteutetaan tehtäviä: RecursiveTask ja RecursiveAction. Molemmat vaativat abstraktin compute()-metodin toteutuksen. RecursiveTask-luokassa compute()-metodi palauttaa arvon, kun taas RecursiveAction-luokassa compute()-metodi ei palauta arvoa.
Main.java
12345678class ExampleTask extends RecursiveTask<String> { @Override protected String compute() { // code return null; } }
Kun perimme luokasta RecursiveTask, meidän on varmistettava, että määrittelemme palautettavan tietotyypin compute()-metodille käyttämällä syntaksia RecursiveTask<String>.
Main.java
1234567class ExampleAction extends RecursiveAction { @Override protected void compute() { // code } }
Tässä tapauksessa päinvastoin, meidän ei tarvitse määritellä tyyppiä erikseen RecursiveAction-luokassa, koska metodimme ei palauta mitään, vaan suorittaa vain tehtävän.
Tehtävän käynnistäminen
Voimme muuten käynnistää tehtävän suoritettavaksi ilman ForkJoinPool-luokan käyttöä, pelkästään käyttämällä fork()- ja join()-menetelmiä.
On tärkeää huomata, että fork()-menetelmä lähettää tehtävän jollekin säikeelle. join()-menetelmää käytetään tuloksen hakemiseen.
Main.java
12345public static void main(String[] args) { ExampleTask simpleClass = new ExampleTask(); simpleClass.fork(); System.out.println(simpleClass.join()); }
ForkJoinPoolin päämenetelmät
invoke(): Käynnistää tehtävän poolissa ja odottaa sen valmistumista. Palauttaa tehtävän suorituksen tuloksen;submit(): Lähettää tehtävän pooliin, mutta ei estä nykyistä säiettä odottamaan tehtävän valmistumista. Voidaan käyttää tehtävien lähettämiseen ja niidenFuture-olioiden hakemiseen;execute(): Suorittaa tehtävän poolissa, mutta ei palauta tulosta eikä estä nykyistä säiettä.
Kuinka voimme käynnistää tehtävän käyttäen ForkJoinPool, hyvin yksinkertaista!
Main.java
12345public static void main(String[] args) { ExampleAction simpleClass = new ExampleAction(); ForkJoinPool forkJoinPool = new ForkJoinPool(); System.out.println(forkJoinPool.invoke(simpleClass)); }
Mutta mikä on ero suorittaa fork(), join() ja käyttää ForkJoinPool -luokkaa?
Se on hyvin yksinkertaista! Kun käytetään ensimmäistä menetelmää fork()- ja join()-metodien avulla, tehtävä käynnistetään samassa säikeessä, jossa nämä metodit kutsutaan, tukien tämän säikeen, kun taas ForkJoinPool-luokan avulla säie varataan säiepoolista ja se suorittaa tehtävän tässä säikeessä ilman, että pääsäiettä tukitaan.
Tarkastellaanpa tarkemmin, oletetaan että meillä on tällainen toteutus:
Main.java
12345678class ExampleRecursiveTask extends RecursiveTask<String> { @Override protected String compute() { System.out.println("Thread: " + Thread.currentThread().getName()); return "Wow, it works!!!"; } }
Ja haluamme suorittaa tämän koodin käyttäen fork() ja join(). Katsotaanpa, mitä tulostuu konsoliin ja mikä säie suorittaa tämän tehtävän.
Main.java
1234567public class Main { public static void main(String[] args) { ExampleRecursiveTask simpleClass = new ExampleRecursiveTask(); simpleClass.fork(); System.out.println(simpleClass.join()); } }
Ja saamme seuraavan tulosteen konsoliin:
Thread: main
Wow, it works!!!
Tarkastellaan nyt, mitä tapahtuu, kun ajetaan ForkJoinPool-luokalla:
Main.java
1234567public class Main { public static void main(String[] args) { ExampleRecursiveTask simpleClass = new ExampleRecursiveTask(); ForkJoinPool forkJoinPool = new ForkJoinPool(); System.out.println(forkJoinPool.invoke(simpleClass)); } }
Ja tästä saadaan seuraava johtopäätös:
Thread: ForkJoinPool-1-worker-1
Wow, it works!!!
Kuten huomaat, ero on siinä, että käytettäessä ensimmäistä menetelmää tehtävä suoritetaan samassa säikeessä, joka kutsui tämän tehtävän (pääsäie). Mutta jos käytämme toista menetelmää, säie otetaan ForkJoinPool-säiepoolista ja pääsäie, joka kutsui tämän logiikan, ei esty vaan jatkaa eteenpäin!
Kuinka toteuttaa Fork/Join koodissa
Tätä on helpointa havainnollistaa videolla sen sijaan, että annettaisiin 50–80 riviä koodia ja selitettäisiin sitä kohta kohdalta.
ForkJoinPool soveltuu tehokkaasti tehtäviin, jotka voidaan helposti jakaa pienempiin osatehtäviin. Jos tehtävät ovat kuitenkin liian pieniä, ForkJoinPool-ratkaisun käyttö ei välttämättä tuo merkittävää suorituskykyetua.
Kiitos palautteestasi!
Kysy tekoälyä
Kysy tekoälyä
Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme
Awesome!
Completion rate improved to 3.33
Forkjoinpool
Pyyhkäise näyttääksesi valikon
ForkJoinPool-luokka Javassa Fork/Join-kehystä varten on juuri tämän toteutus. Se tarjoaa mekanismit tehtävien hallintaan, jotka voidaan jakaa pienempiin osatehtäviin ja suorittaa rinnakkain.
Main.java
1ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinPool perustuu kahteen perustoimintoon: fork ja join. Fork tarkoittaa toimintoa, jossa suuri tehtävä jaetaan useisiin pienempiin osatehtäviin, jotka voidaan suorittaa rinnakkain. Join on prosessi, jossa näiden osatehtävien tulokset yhdistetään alkuperäisen tehtävän tulokseksi.
Tapaustutkimus
Kuvittele, että sinun täytyy analysoida valtava tietoaineisto, joka voidaan jakaa useisiin pienempiin osiin. Jos käsittelet jokaisen tietoaineiston erikseen ja sitten yhdistät tulokset, voit nopeuttaa käsittelyä merkittävästi, erityisesti moniprosessorijärjestelmissä.
ForkJoinPoolin käyttö
On olemassa 2 luokkaa, joilla toteutetaan tehtäviä: RecursiveTask ja RecursiveAction. Molemmat vaativat abstraktin compute()-metodin toteutuksen. RecursiveTask-luokassa compute()-metodi palauttaa arvon, kun taas RecursiveAction-luokassa compute()-metodi ei palauta arvoa.
Main.java
12345678class ExampleTask extends RecursiveTask<String> { @Override protected String compute() { // code return null; } }
Kun perimme luokasta RecursiveTask, meidän on varmistettava, että määrittelemme palautettavan tietotyypin compute()-metodille käyttämällä syntaksia RecursiveTask<String>.
Main.java
1234567class ExampleAction extends RecursiveAction { @Override protected void compute() { // code } }
Tässä tapauksessa päinvastoin, meidän ei tarvitse määritellä tyyppiä erikseen RecursiveAction-luokassa, koska metodimme ei palauta mitään, vaan suorittaa vain tehtävän.
Tehtävän käynnistäminen
Voimme muuten käynnistää tehtävän suoritettavaksi ilman ForkJoinPool-luokan käyttöä, pelkästään käyttämällä fork()- ja join()-menetelmiä.
On tärkeää huomata, että fork()-menetelmä lähettää tehtävän jollekin säikeelle. join()-menetelmää käytetään tuloksen hakemiseen.
Main.java
12345public static void main(String[] args) { ExampleTask simpleClass = new ExampleTask(); simpleClass.fork(); System.out.println(simpleClass.join()); }
ForkJoinPoolin päämenetelmät
invoke(): Käynnistää tehtävän poolissa ja odottaa sen valmistumista. Palauttaa tehtävän suorituksen tuloksen;submit(): Lähettää tehtävän pooliin, mutta ei estä nykyistä säiettä odottamaan tehtävän valmistumista. Voidaan käyttää tehtävien lähettämiseen ja niidenFuture-olioiden hakemiseen;execute(): Suorittaa tehtävän poolissa, mutta ei palauta tulosta eikä estä nykyistä säiettä.
Kuinka voimme käynnistää tehtävän käyttäen ForkJoinPool, hyvin yksinkertaista!
Main.java
12345public static void main(String[] args) { ExampleAction simpleClass = new ExampleAction(); ForkJoinPool forkJoinPool = new ForkJoinPool(); System.out.println(forkJoinPool.invoke(simpleClass)); }
Mutta mikä on ero suorittaa fork(), join() ja käyttää ForkJoinPool -luokkaa?
Se on hyvin yksinkertaista! Kun käytetään ensimmäistä menetelmää fork()- ja join()-metodien avulla, tehtävä käynnistetään samassa säikeessä, jossa nämä metodit kutsutaan, tukien tämän säikeen, kun taas ForkJoinPool-luokan avulla säie varataan säiepoolista ja se suorittaa tehtävän tässä säikeessä ilman, että pääsäiettä tukitaan.
Tarkastellaanpa tarkemmin, oletetaan että meillä on tällainen toteutus:
Main.java
12345678class ExampleRecursiveTask extends RecursiveTask<String> { @Override protected String compute() { System.out.println("Thread: " + Thread.currentThread().getName()); return "Wow, it works!!!"; } }
Ja haluamme suorittaa tämän koodin käyttäen fork() ja join(). Katsotaanpa, mitä tulostuu konsoliin ja mikä säie suorittaa tämän tehtävän.
Main.java
1234567public class Main { public static void main(String[] args) { ExampleRecursiveTask simpleClass = new ExampleRecursiveTask(); simpleClass.fork(); System.out.println(simpleClass.join()); } }
Ja saamme seuraavan tulosteen konsoliin:
Thread: main
Wow, it works!!!
Tarkastellaan nyt, mitä tapahtuu, kun ajetaan ForkJoinPool-luokalla:
Main.java
1234567public class Main { public static void main(String[] args) { ExampleRecursiveTask simpleClass = new ExampleRecursiveTask(); ForkJoinPool forkJoinPool = new ForkJoinPool(); System.out.println(forkJoinPool.invoke(simpleClass)); } }
Ja tästä saadaan seuraava johtopäätös:
Thread: ForkJoinPool-1-worker-1
Wow, it works!!!
Kuten huomaat, ero on siinä, että käytettäessä ensimmäistä menetelmää tehtävä suoritetaan samassa säikeessä, joka kutsui tämän tehtävän (pääsäie). Mutta jos käytämme toista menetelmää, säie otetaan ForkJoinPool-säiepoolista ja pääsäie, joka kutsui tämän logiikan, ei esty vaan jatkaa eteenpäin!
Kuinka toteuttaa Fork/Join koodissa
Tätä on helpointa havainnollistaa videolla sen sijaan, että annettaisiin 50–80 riviä koodia ja selitettäisiin sitä kohta kohdalta.
ForkJoinPool soveltuu tehokkaasti tehtäviin, jotka voidaan helposti jakaa pienempiin osatehtäviin. Jos tehtävät ovat kuitenkin liian pieniä, ForkJoinPool-ratkaisun käyttö ei välttämättä tuo merkittävää suorituskykyetua.
Kiitos palautteestasi!