Kollégától kaptam, megmutatom neked is:
int[] arr = new int[64 * 1024 * 1024]; // Loop 1 for (int i = 0; i < arr.Length; i++) arr[i] *= 3; // Loop 2 for (int i = 0; i < arr.Length; i += 16) arr[i] *= 3;
Melyik a gyorsabb? Az implementációs nyelv legyen mondjuk… java.
Megoldás a folytatásban.
A megoldás: egyik sem, a futási idejük 0. A JVM defaultban 64Mb memóriát foglal a heapben, és a kód már az első sorban megpróbál ~130Mb-t foglalni, futásidejű, végzetessel elszáll.
Komolyra fordítva, bár azt hinnéd, a loop 2 fog rövidebb idő alatt végezni (hiszen harmad annyi iterációt végez), a gyakorlat azt mutatja, hogy a két iteráció futási ideje megegyezik. Ez azért van (már, ha jól értettem) mert a matekolás kisebb erőforrás igényű, mint a memória olvasás. Manapság nem byteonként olvassuk a memóriát, hanem cachelve, és emiatt a kérdéses tömbelem kiolvasása ugyanannyiba fog kerülni. Részletesen, meg hasonló okosságok itt. Olvasd, értelmezd.
A fentiek, ahogy kivettem, natív binárisra érvényesek. Írtam egy Java tesztet, aminek a kimenete:
Init in: 615 ms Round: 1 Loop 1: 267 ms Loop 2: 176 ms Round: 2 Loop 1: 260 ms Loop 2: 177 ms Round: 3 Loop 1: 263 ms Loop 2: 180 ms Round: 4 Loop 1: 261 ms Loop 2: 181 ms Round: 5 Loop 1: 316 ms Loop 2: 181 ms
Tehát, a loop 1 átlag ~ 1,5* tovább tart mint a loop2 2. Node, mi van akkor, ha felcseréljük a kódban az iteráció helyét?
Init in: 424 ms Round: 1 Loop 2: 182 ms Loop 1: 181 ms Round: 2 Loop 2: 226 ms Loop 1: 202 ms Round: 3 Loop 2: 183 ms Loop 1: 184 ms Round: 4 Loop 2: 179 ms Loop 1: 182 ms Round: 5 Loop 2: 178 ms Loop 1: 188 ms
Akkor bizony közel egyforma hosszan futnak. Jó, mi? És mielőtt bárki is azt mondaná, hogy azért mert csak egyszer inicializáltam a tömböt, kipróbáltam úgy, hogy minden iteráció előtt újra inicializáltam a tömböket, és nincs lényegi különbség az eredmények közt, ugyan ez a tendencia. Tuti, hogy itt is valami cache dolog játszik be, de hogy pontosan mi, ahhoz kevés vagyok.