Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: Zelenac 19. 03. 2016, 13:00:43

Název: Java Lambdas jsou několikanásobně pomalejší
Přispěvatel: Zelenac 19. 03. 2016, 13:00:43
Jak uz zde nekteri mi priznivci vedi, mam rad eventy a Javu, a tak jsem si zkousel zmerit rychlost standardnich konstrukci s temi lamdovskymi a ve vsech pripadech mi vyslo, ze lambdy jsou pomalejsi, v nekterych pripadech az nekolikanasobne. A ja blahovy jsem si myslel, ze lambdy v pozadi konecne funguji jako primy vstup do metody/funkce, a ono zrejme ne. Dela se z nich az moc velke terno ale je to fakt slabota. Zejo?
Název: Re:Java Lamdas slow as fak
Přispěvatel: Zelenac 19. 03. 2016, 13:14:01
Kód: [Vybrat]
package main;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BinaryOperator;

class Parameters {
public final int p1;
public final int p2;
public Parameters(int p1, int p2) {
this.p1 = p1;
this.p2 = p2;
}
}

class Main {

static final long SIZE = 50000000;

static long tsuma = 0;

public static void sum(long val) {
tsuma += val;
}

public static int vypocet(Parameters params) {
return params.p1 * params.p2;
}


public static void main(String[] args) {
List<Long> list = new ArrayList<>();
for(long i = 0; i < SIZE/3; i++ ) {
list.add(i);
}

long timer;
long supp;

/**
* Obycejny se statickou metodou
*/
timer = System.nanoTime();
for(int i = 0; i < list.size(); i++)
sum(list.get(i));
timer = System.nanoTime() - timer;
System.out.println(timer + " " + tsuma);

/*
* Lambda se statickou metodou
*/
tsuma = 0;
timer = System.nanoTime();
list.forEach( (value) -> sum(value) );
timer = System.nanoTime() - timer;
System.out.println(timer +" " + tsuma);

/**
* Lambda se streamem
*/
supp = 0;
timer = System.nanoTime();
supp = list.stream().mapToLong(value -> value).reduce(1, (a, b) -> a += b );
timer = System.nanoTime() - timer;
System.out.println(timer + " " + supp);


/**
* Volani pres new bez lambdy
*/
supp = 0;
timer = System.nanoTime();
for(int i = 0; i < SIZE; i++) {
supp += vypocet(new Parameters(i, i));
}
timer = System.nanoTime() - timer;
System.out.println(timer + " " + supp);


/**
* Lambda
*/
BinaryOperator<Integer> op = (a, b) -> { return a * b; };
supp = 0;
timer = System.nanoTime();
for(int i = 0; i < SIZE; i++) {
supp += op.apply(i, i);
}
timer = System.nanoTime() - timer;
System.out.println(timer + " " + supp);
}
}



výstup:

Kód: [Vybrat]
35440642 ns   
77238271 ns
40472188 ns   
37840783 ns     
1874345240 ns  //zatracene pomala lambda

Název: Re:Java Lamdas slow as fak
Přispěvatel: Ondra Satai Nekola 19. 03. 2016, 13:20:57
- takhle se mikrobenchmarky nikdy nemohou psat
- pokud te prekvapuje, ze netere kusy tohohle kodu budou pomalejsi, nez jine, tak se zamysli nad tim, jak se to preklada. (aha "A ja blahovy jsem si myslel, ze lambdy v pozadi konecne funguji jako primy vstup do metody/funkce" rika vsechno)
Název: Re:Java Lamdas slow as fak
Přispěvatel: Zelenac 19. 03. 2016, 13:27:19
Dle speciální matematicko-redukční metody vyplynulo, že s benchmarky napsanými takhle pod sebeou se vejdu do tolerance +-0.3569991%  relativně k benchmarkům spouštěným zvlášť. [1]

[1] Jan Amos Komínský, Highest Computer Scientist Methodology in Java, 2016, CERN
Název: Re:Java Lamdas slow as fak
Přispěvatel: Ondra Satai Nekola 19. 03. 2016, 14:26:20
Dle speciální matematicko-redukční metody vyplynulo, že s benchmarky napsanými takhle pod sebeou se vejdu do tolerance +-0.3569991%  relativně k benchmarkům spouštěným zvlášť. [1]

[1] Jan Amos Komínský, Highest Computer Scientist Methodology in Java, 2016, CERN

Tak sis zatroloval a s tim bychom to mohli asi uzavrit...
Název: Re:Java Lamdas slow as fak
Přispěvatel: zboj 19. 03. 2016, 14:30:03
Jak uz zde nekteri mi priznivci vedi, mam rad eventy a Javu, a tak jsem si zkousel zmerit rychlost standardnich konstrukci s temi lamdovskymi a ve vsech pripadech mi vyslo, ze lambdy jsou pomalejsi, v nekterych pripadech az nekolikanasobne. A ja blahovy jsem si myslel, ze lambdy v pozadi konecne funguji jako primy vstup do metody/funkce, a ono zrejme ne. Dela se z nich az moc velke terno ale je to fakt slabota. Zejo?

Změň jazyk ;)
Název: Re:Java Lamdas slow as fak
Přispěvatel: javaman 19. 03. 2016, 14:34:42
Jak uz zde nekteri mi priznivci vedi, mam rad eventy a Javu, a tak jsem si zkousel zmerit rychlost standardnich konstrukci s temi lamdovskymi a ve vsech pripadech mi vyslo, ze lambdy jsou pomalejsi, v nekterych pripadech az nekolikanasobne. A ja blahovy jsem si myslel, ze lambdy v pozadi konecne funguji jako primy vstup do metody/funkce, a ono zrejme ne. Dela se z nich az moc velke terno ale je to fakt slabota. Zejo?

Změň jazyk ;)

Tak určitě, ať zahodí ten nejlepší a jde do nějakého horšího. Takhle se to nedělá. Nejdříve se naučím jeden dobře a až pak se dívám jinam. Hlavně měl štěstí, protože si vybral zrovna to nejlepší. Jen tomu musí věnovat pár let, aby se dostal na trochu lepší úroveň.
Název: Re:Java Lamdas slow as fak
Přispěvatel: M 19. 03. 2016, 14:38:31
Zacni pouzivat C#, jediny jazyk, ktery ma vsechno smysluplne.
Název: Re:Java Lamdas slow as fak
Přispěvatel: zboj 19. 03. 2016, 14:43:42
Jak uz zde nekteri mi priznivci vedi, mam rad eventy a Javu, a tak jsem si zkousel zmerit rychlost standardnich konstrukci s temi lamdovskymi a ve vsech pripadech mi vyslo, ze lambdy jsou pomalejsi, v nekterych pripadech az nekolikanasobne. A ja blahovy jsem si myslel, ze lambdy v pozadi konecne funguji jako primy vstup do metody/funkce, a ono zrejme ne. Dela se z nich az moc velke terno ale je to fakt slabota. Zejo?

Změň jazyk ;)

Tak určitě, ať zahodí ten nejlepší a jde do nějakého horšího. Takhle se to nedělá. Nejdříve se naučím jeden dobře a až pak se dívám jinam. Hlavně měl štěstí, protože si vybral zrovna to nejlepší. Jen tomu musí věnovat pár let, aby se dostal na trochu lepší úroveň.
Nikdo neříkal, ať zahodí nejlepší. Řeč byla o Javě ;)
Název: Re:Java Lamdas slow as fak
Přispěvatel: javaman 19. 03. 2016, 14:45:12
To právě nechápu. Stačí ji umět a nic lepšího nenajdeš. Proto je Java taky všude, že jo.
Název: Re:Java Lamdas slow as fak
Přispěvatel: Ondra Satai Nekola 19. 03. 2016, 15:40:59
To právě nechápu. Stačí ji umět a nic lepšího nenajdeš. Proto je Java taky všude, že jo.

No to bych nerekl. Java je vsude, protoze je to slusne navrzeny mainstream, co mel stesti. Ale ze by to bylo "nic lepsiho nenajdes", tak to urcite ne. Uz jenom, pokud zustaneme na JVM, je pro nektere veci (unittesty se Spockem jsou pekny priklad) lepsi Groovy, Kotlin zakulatil syntaxi, nektere veci lepe napises ve Scale...
Název: Re:Java Lamdas slow as fak
Přispěvatel: kvr kvr 19. 03. 2016, 15:50:24
Je tam nekolik problemu:

JIT optimalizuje az po nekolika (tisicich) pusteni dane funkcr. Proto je vhodne zvolit nejaky microbenchmark tool  - JHM treba a korektne napsat benchmarky.

Zalezi jak se napise kod. Vytvaret lambdu pro kazdy prvek, kdyz se vlasyne nemeni, je zcela zbytecne, navic by se o to mozna prave postaral JIT. I tak normalne by to nevadilo, ale v takovem umelem benchmatk se to pochopitelne projevi.

Posledni priklad - letmo - vytvari pro kazde volani 3x Integer class. Zatimco u for verze kompolator nejspis zcela vyhodi ten temporary objekt ci ho da na stack, takze vysledkem bude zcela primy preklad pres par scitani.

Je treba rict, ze lambda je ve sve podstate virtualni callback, ktery negativne ovlivnuje moznosti optimalizace. Bezne to nevadi, bo moderni SW je na tom postaveny, ale v pripade jednoduchych matematickych smycek typu secti mi pole cisel to neni nejlepsi varianta.

Ale jeste jednou viz vyse - dost mozna cast vyresi JIT po vice pruchodech.
Název: Re:Java Lamdas slow as fak
Přispěvatel: Ziktofel 19. 03. 2016, 16:14:05
nezdrzuje to nahodou ten autoboxing/unboxing?
Název: Re:Java Lamdas slow as fak
Přispěvatel: Pavel Tisnovsky 19. 03. 2016, 19:27:16
Zkus si ten kod vyhodit do dalsi metody a tu spoustet n-krat (kde n bude dostatecne velke cislo), pak si udelej tabulku s casy, jestli (a ktere) se zlepsi atd. Protoze JIT tady funguje mozna trosku jinak nez ocekavas.

Taky je zajimavy se mrknout na vygenerovany bajtkod, ono tam bude (jak pise ziktofel) dost operaci s auto(un)boxingem. To sice JIT taky pochopi a odstrani, ale musi se napred spustit, aby dostal sanci :)
Název: Re:Java Lamdas slow as fak
Přispěvatel: Zelenac 19. 03. 2016, 21:10:03
Takže ne lambda, ale java jitr slow as fak. No a co lambdy a JavaFX eventy, tam mi to vylozene prijde ze eventy ve swingu jsou praktičtější, proste dam addListener(new Handler(){..} ) a prepisu si eventy na ktere chci reagovat v jedinem  addListenerovi, navic je to i prenositelnejs na starsi jdk.
Název: Re:Java Lamdas slow as fak
Přispěvatel: Natix 19. 03. 2016, 21:49:14
Pokud zůstaneme jenom u posledních dvou příkladů, tak drobnou změnou lze dostat výrazně jiné výsledky:

řádku

Kód: [Vybrat]
supp += vypocet(new Parameters(i, i));
nahradíme

Kód: [Vybrat]
supp += Integer.valueOf(i) * Integer.valueOf(i);
Výsledek měření:

Kód: [Vybrat]
1 106 232 471 ns
1 286 946 604 ns

Jde o to, že v případě ručního boxingu pomocí třídy Parameters se alokuje jeden objekt za iteraci, zatímco u autoboxingu se alokují objekty dva. Použití Parameters je díky tomu skoro 2x rychlejší:

Kód: [Vybrat]
707 933 084 ns
1 256 313 255 ns

V předcházejících třech případech se provádí jenom unboxing, takže jsou pochopitelně rychlejší.
Název: Re:Java Lamdas slow as fak
Přispěvatel: Pavel Tisnovsky 19. 03. 2016, 21:52:44
Takže ne lambda, ale java jitr slow as fak. No a co lambdy a JavaFX eventy, tam mi to vylozene prijde ze eventy ve swingu jsou praktičtější, proste dam addListener(new Handler(){..} ) a prepisu si eventy na ktere chci reagovat v jedinem  addListenerovi, navic je to i prenositelnejs na starsi jdk.

Nee, JIT ma urcite vlastnosti, kdy se spusti a jak funguje. Pokud se navic napise neekvivalentni kod (coz ta posledni cast je), tak se to proste nedava dobre porovnavat.

Spis se zeptam - je to problem v realne aplikaci, nebo Te zajima, proc je to skutecne pomale? V prvnim pripade - uz to neres, sam vidis, ze prvni reseni je rychlejsi, problem solved, muzes resit dalsi problemy. Pokud je to druhy priklad, tak je skutecne dobre se podivat na ten bajtkod.
Název: Re:Java Lamdas slow as fak
Přispěvatel: Natix 19. 03. 2016, 21:57:28
A ještě dodatek: I použití lambdy jde výrazně zrychlit použitím neboxující lambdy:

Pokud místo
Kód: [Vybrat]
BinaryOperator<Integer> op = (a, b) -> a * b;použijeme
Kód: [Vybrat]
IntBinaryOperator op = (a, b) -> a * b;tak dostaneme časy:
Kód: [Vybrat]
718 975 989 ns
382 852 492 ns

Je ovšem otázka, jestli v reálném softwaru je takovýto rozdíl v performance skutečným problémem či ne, a zda znečištění javovského API explozí primitivních variant všech funkcionálních interfaců stálo za to.
Název: Re:Java Lamdas slow as fak
Přispěvatel: čumil 20. 03. 2016, 00:16:28
Jak uz zde nekteri mi priznivci vedi, mam rad eventy a Javu, a tak jsem si zkousel zmerit rychlost standardnich konstrukci s temi lamdovskymi a ve vsech pripadech mi vyslo, ze lambdy jsou pomalejsi, v nekterych pripadech az nekolikanasobne. A ja blahovy jsem si myslel, ze lambdy v pozadi konecne funguji jako primy vstup do metody/funkce, a ono zrejme ne. Dela se z nich az moc velke terno ale je to fakt slabota. Zejo?

Změň jazyk ;)

Tak určitě, ať zahodí ten nejlepší a jde do nějakého horšího. Takhle se to nedělá. Nejdříve se naučím jeden dobře a až pak se dívám jinam. Hlavně měl štěstí, protože si vybral zrovna to nejlepší. Jen tomu musí věnovat pár let, aby se dostal na trochu lepší úroveň.
Nezapomeň na domácí úkoli a ten test z matematiky příští pondělí synu.
Název: Re:Java Lamdas slow as fak
Přispěvatel: Lol Phirae 20. 03. 2016, 00:30:41
http://turnoff.us/geek/a-java-nightmare/