Rohkem
Miks on 2 * (i * i) kiirem kui 2 * i * i Javas?
Järgmise Java-programmi käivitamine võtab keskmiselt 0,50 sekundit kuni 0,55 sekundit:
public static void main(String[] args) {
long startTime = System.nanoTime();
int n = 0;
for (int i = 0; i < 1000000000; i++) {
n += 2 * (i * i);
}
System.out.println((double) (System.nanoTime() - startTime) / 1000000000 + " s");
System.out.println("n = " + n);
}
Kui ma asendan 2 * (i * i)
programmiga 2 * i * i
, kulub selle käivitamiseks 0,60 kuni 0,65 sekundit. Kuidas on see võimalik?
Ma jooksutasin mõlemat programmi versiooni 15 korda, vaheldumisi. Siin on tulemused:
2*(i*i) | 2*i*i
----------+----------
0.5183738 | 0.6246434
0.5298337 | 0.6049722
0.5308647 | 0.6603363
0.5133458 | 0.6243328
0.5003011 | 0.6541802
0.5366181 | 0.6312638
0.515149 | 0.6241105
0.5237389 | 0.627815
0.5249942 | 0.6114252
0.5641624 | 0.6781033
0.538412 | 0.6393969
0.5466744 | 0.6608845
0.531159 | 0.6201077
0.5048032 | 0.6511559
0.5232789 | 0.6544526
Kiireim käivitamine 2 * i * i
võttis kauem aega kui kõige aeglasem käivitamine 2 * (i * i)
. Kui mõlemad oleksid sama tõhusad, oleks selle tõenäosus väiksem kui 1/2^15 * 100% = 0,00305%.
833
3
Baidikoodid: https://cs.nyu.edu/courses/fall00/V22.0201-001/jvm2.html Baitikoodid Viewer: https://github.com/Konloch/bytecode-viewer
Minu JDK (Windows 10 64 bit, 1.8.0_65-b17) ma saan reprodutseerida ja selgitada:
Väljund:
Miks siis? Baitkood on selline:
Erinevus on: Sulgudes (
2 * (i * i)
):Ilma sulgudeta (
2 * i * i
):Kõike korstnasse laadimine ja seejärel tagasi töötamine on kiirem kui korstnasse panemise ja korstnas töötamise vahel ümberlülitamine.
Sain sarnaseid tulemusi:
Ma sain SAME tulemused, kui mõlemad silmused olid samas programmis või mõlemad olid eraldi .java failis/.classis, mida käivitati eraldi.
Lõpuks on siin
javap -c -v
dekompileerimine mõlemast:vs.
FYI -
Need kaks lisamismeetodit genereerivad veidi erinevat baitkoodi:
Sest
2 * (i * i)
vs:For
2 * i * i
.Ja kui kasutada JMH võrdlusnäitajat, nagu see:
Erinevus on selge:
See, mida te täheldate, on õige ja mitte lihtsalt teie võrdlusuuringu stiili anomaalia (st ei ole soojendust, vt Kuidas kirjutada õiget mikromarki Java's?).
Käivitan uuesti Graaliga:
Näete, et tulemused on palju lähemal, mis on mõistlik, kuna Graal on üldiselt parema jõudlusega, kaasaegsem kompilaator.
Nii et see sõltub tegelikult lihtsalt sellest, kui hästi JIT-kompilaator suudab konkreetset koodi optimeerida, ja sellel ei pruugi olla loogilist põhjust.