Yleiset sudenkuopat
Järjestys, boxing ja yhteinen säieallas.
Yleiset sudenkuopat on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.
Rinnakkaisuus ei tarkoita ilmaista nopeutta
parallel()-operaation lisääminen voi hidastaa koodia nopeuttamisen sijaan. Tässä oppitunnissa käsitellään tavalliset sudenkuopat, jotta voitte välttää ne.
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
long sum = IntStream.rangeClosed(1, 1_000_000).parallel()
.asLongStream().sum();
System.out.println(sum);
}
}Sudenkuoppa: järjestyksen aiheuttama yleiskustannus
Järjestystä säilyttävät operaatiot, kuten forEachOrdered tai limit, pakottavat säikeet koordinoimaan toimintaansa, mikä heikentää rinnakkaisuuden hyötyjä.
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
IntStream.rangeClosed(1, 5).parallel()
.forEachOrdered(System.out::println);
}
}unordered voi auttaa
Jos järjestyksellä ei ole merkitystä, unordered()-kutsulla ajonaikainen ympäristö voi ohittaa järjestykseen liittyvän työn ja rinnakkaistaa suoritusta vapaammin.
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
long count = IntStream.rangeClosed(1, 1_000_000).parallel()
.unordered()
.filter(n -> n % 5 == 0)
.count();
System.out.println(count);
}
}Sudenkuoppa: piilevä boxing
Stream<Integer>-tyypin käyttäminen rinnakkain moninkertaistaa boxingin kustannukset säikeiden välillä. Suosikaa numeerisessa rinnakkaistyössä primitiivivirtoja.
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
long sum = IntStream.rangeClosed(1, 1_000_000).parallel().asLongStream().sum();
System.out.println(sum);
}
}Sudenkuoppa: jaettu yhteinen pooli
Kaikki rinnakkaiset virrat käyttävät samaa ForkJoinPool.commonPool()-poolia. Pitkä rinnakkainen tehtävä voi estää muita saman JVM:n tehtäviä, mukaan lukien sovelluksen muut osat.
import java.util.concurrent.ForkJoinPool;
public class Main {
public static void main(String[] args) {
System.out.println(ForkJoinPool.commonPool().getParallelism());
}
}Työn eristäminen mukautettuun pooliin
Jotta raskas työ pysyy yhteisen poolin ulkopuolella, suorittakaa rinnakkainen virta oman ForkJoinPool-poolinne sisällä.
import java.util.concurrent.ForkJoinPool;
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) throws Exception {
ForkJoinPool pool = new ForkJoinPool(2);
long sum = pool.submit(() ->
IntStream.rangeClosed(1, 1_000_000).parallel().asLongStream().sum()
).get();
pool.shutdown();
System.out.println(sum);
}
}Sudenkuoppa: huonosti jaettavat lähteet
LinkedList, Stream.iterate ja BufferedReader.lines jakautuvat huonosti. Niiden rinnakkaistamisesta on usein vain vähän hyötyä tai se voi jopa heikentää suorituskykyä.
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
long n = Stream.iterate(1, x -> x + 1)
.limit(100_000)
.parallel()
.filter(x -> x % 2 == 0)
.count();
System.out.println(n);
}
}Sudenkuoppa: tilalliset lambdat
Ulkoista tilaa lukevat tai kirjoittavat lambdat toimivat rinnakkain epädeterministisesti. Pitäkää ne tilattomina, jotta saatte yhdenmukaisia tuloksia.
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
int sum = IntStream.rangeClosed(1, 100).parallel()
.map(n -> n + 1)
.sum();
System.out.println(sum);
}
}Sudenkuoppa: findFirst vastaan findAny
findFirst-operaation on noudatettava järjestystä, mikä lisää rinnakkaisen suorituksen kustannuksia. Jos mikä tahansa täsmäävä alkio kelpaa, käyttäkää findAny-operaatiota.
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
int found = IntStream.rangeClosed(1, 1_000_000).parallel()
.filter(n -> n % 99991 == 0)
.findAny()
.getAsInt();
System.out.println(found);
}
}Sudenkuoppa: kevyet operaatiot pienellä datalla
Pienillä kokoelmilla tai vähäisellä työllä osiin jakamisen ja yhdistämisen yleiskustannus on paljon suurempi kuin mahdollinen hyöty. Pysykää peräkkäisessä suorituksessa.
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> small = List.of(1, 2, 3, 4);
int sum = small.stream().mapToInt(Integer::intValue).sum();
System.out.println(sum);
}
}Sudenkuoppa: kerääjien kallis yhdistäminen
Kalliin yhdistämisvaiheen sisältävät kerääjät, kuten suurten järjestettyjen rakenteiden muodostajat, voivat mitätöidä rinnakkaisuuden hyödyt. Yksinkertaiset kerrytykset yhdistyvät edullisesti.
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) {
long total = IntStream.rangeClosed(1, 1_000_000).parallel()
.mapToLong(n -> n)
.sum();
System.out.println(total);
}
}Pikatarkistus
Miksi findFirst voi olla rinnakkaisessa virrassa hitaampi kuin findAny?
Kertaus
Opitte rinnakkaisuuden tavalliset sudenkuopat:
- Järjestyksen säilyttäminen (
forEachOrdered,limit,findFirst) lisää koordinoinnin kustannuksia; käyttäkää mahdollisuuksien mukaanunordered- taifindAny-operaatiota. - Boxing moninkertaistaa kustannukset; suosikaa primitiivivirtoja.
- Jaettu yhteinen pooli voi estyä; eristäkää raskas työ mukautettuun
ForkJoinPool-pooliin. - Huonosti jaettavat lähteet, pieni datamäärä ja kallis yhdistäminen heikentävät kaikki rinnakkaisuuden hyötyä.
Opi Java tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 104
- Oppitunnit
- 374
Usein kysytyt kysymykset
Onko oppitunti ”Yleiset sudenkuopat” ilmainen?
Kyllä – oppitunnin ”Yleiset sudenkuopat” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Yleiset sudenkuopat”?
Järjestys, boxing ja yhteinen säieallas. Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.
Kuinka kauan ”Yleiset sudenkuopat”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?
Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Rinnakkaisvirtojen luonti
- Milloin rinnakkaisuus auttaa
- Säieturvallisuus ja sivuvaikutukset
- Yleiset sudenkuopat