Što mislite, jesu li ova dva načina provjere uvjeta unutar petlje ekvivalentni u pogledu performansi?
if a > b && c*2 > d {
....
}
// i
if a d {
....
}
Sve je počelo s 'zagrijavanjem za mozak', trebalo je dati primjer optimalne pretrage u nizu cijelih brojeva [-x….x] za najveći parni broj. Pitao sam se koliko će performanse biti bolje ako se za utvrđivanje parnosti broja koristi logičko množenje s 1.
//у четных чисел последний бит всегда равен 0
value & 1 == 0
//vs классический метод
value % 2 == 0
Moje iskustvo programiranja u Go-u nije baš veliko, malo više od godinu i pol, koristio sam ga često, ali isključivo u utilitarnim svrhema (možda osim jednog projekta vezanog za visoko opterećen http servis), stoga sam započeo upravo s njim. Otvorimo GoLand i pišemo jednostavan test
package main
import (
"fmt"
"log"
"math"
"math/rand"
"time"
)
const size = 100000000 //math.MaxInt32*2
type Result struct {
Name string
Duration time.Duration
Value int32
}
func main() {
log.Println("initial array capacity: " + fmt.Sprint(size))
var maxValue int32
// Varirat ćemo raspon brojeva od minimalnog
// do maksimalnog. Što je raspon manji, to više
// procesorskog vremena će biti potrebno za operaciju
// usporedbe trenutnog broja s prethodno pronađenim i obrnuto
for maxValue = 128; maxValue Dobijamo rezultat koji pokazuje da što je viša granica, to su sve češće fluktuacije u pogledu performansi.
Uporeditemaksimalni prag: 128
maxEvenDividing rezultat: 126 trajanje 116.0067ms
maxEvenConjunction rezultat: 126 trajanje 116.0066ms
max threshold: 16384
maxEvenDividing result: 16382 duration 115.0066ms
maxEvenConjunction result: 16382 duration 111.0064ms
......
max threshold: 8388608
maxEvenDividing result: 8388606 duration 109.0063ms
maxEvenConjunction rezultat: 8388606 trajanje 109.0062ms
maksimalni prag: 16777216
maxEvenDividing rezultat: 16777214 trajanje 108.0062ms
maxEvenConjunction rezultat: 16777214 trajanje 109.0062ms
maksimalni prag: 33554432
maxEvenDividing rezultat: 33554430 trajanje 114.0066ms
maxEvenConjunction rezultat: 33554430 trajanje 110.0063ms
maksimalni prag: 67108864
maxEvenDividing rezultat: 67108860 trajanje 111.0064ms
maxEvenConjunction rezultat: 67108860 trajanje 109.0062ms
maksimalni prag: 134217728
maxEvenDividing rezultat: 134217726 trajanje 108.0062ms
maxEvenConjunction rezultat: 134217726 trajanje 109.0063ms
maksimalni prag: 268435456
maxEvenDividing rezultat: 268435446 trajanje 111.0063ms
maxEvenConjunction rezultat: 268435446 trajanje 110.0063ms
Jasno je da u ovom slučaju, za različite pragove imamo različite skupove testnih podataka, opterećenje CPU-a (na mom laptopu i5-2540M) varira oko 20..30%, memorija koju zauzima aplikacija pokrenuta iz GoLand-a u prosjeku iznosi oko 813MB — to također utječe na pouzdanost rezultata, potrebno je implementirati spremanje testnih skupova na disk i pokrenuti sve testove za svaki prag izolirano jedan od drugog.
I tako, razmišljajući o tome kako to implementirati s minimalnim troškovima, automatski ispravljam provjeru uvjeta
if value > current && value&1 == 0 {
current = value
}
na
if value <= current {
continue;
}
if value&1 == 0 {
current = value
}
ponovo pokrećem testove... i prestajem razumjeti išta 🙂
Vrijeme potrebno za izvršenje počinje se razlikovati ne više od posto / dijela procenta, nego za 10..15%. Brzo dodajem još 2 testa:
func maxEvenDividing2(name string, arr []int32) Result {
start := time.Now()
var current int32 = math.MinInt32
for _, value := range arr {
if value <= current {
continue
}
if value%2 == 0 {
current = value
}
}
duration := time.Since(start)
result := Result{name, duration, current}
return result
}
func maxEvenConjunction2(name string, arr []int32) Result {
start := time.Now()
var current int32 = math.MinInt32
for _, value := range arr {
if value <= current {
continue
}
if value&1 == 0 {
current = value
}
}
duration := time.Since(start)
result := Result{name, duration, current}
return result
}
pokrećem i dobijam ovakvu sliku:prvotna kapacitet niza: 100000000
maksimalni prag: 128
maxEvenDividing rezultat: 126 trajanje 116.0066ms
maxEvenDividing2 rezultat: 126 trajanje 79.0045ms
maxEvenConjunction rezultat: 126 trajanje 114.0065ms
maxEvenConjunction2 rezultat: 126 trajanje 83.0048ms
maksimalni prag: 256
maxEvenDividing rezultat: 254 trajanje 111.0063ms
maxEvenDividing2 rezultat: 254 trajanje 77.0044ms
maxEvenConjunction rezultat: 254 trajanje 110.0063ms
maxEvenConjunction2 rezultat: 254 trajanje 80.0046ms
maksimalni prag: 512
maxEvenDividing rezultat: 510 trajanje 114.0066ms
maxEvenDividing2 rezultat: 510 trajanje 80.0045ms
maxEvenConjunction rezultat: 510 trajanje 110.0063ms
maxEvenConjunction2 rezultat: 510 trajanje 80.0046ms
maksimalni prag: 1024
maxEvenDividing rezultat: 1022 trajanje 109.0063ms
maxEvenDividing2 rezultat: 1022 trajanje 77.0044ms
maxEvenConjunction rezultat: 1022 trajanje 111.0063ms
maxEvenConjunction2 rezultat: 1022 trajanje 81.0047ms
maksimalni prag: 2048
maxEvenDividing rezultat: 2046 trajanje 114.0065ms
maxEvenDividing2 rezultat: 2046 trajanje 79.0045ms
maxEvenConjunction rezultat: 2046 trajanje 113.0065ms
maxEvenConjunction2 rezultat: 2046 trajanje 81.0046ms
maksimalni prag: 4096
maxEvenDividing rezultat: 4094 trajanje 114.0065ms
maxEvenDividing2 rezultat: 4094 trajanje 80.0046ms
maxEvenConjunction rezultat: 4094 trajanje 111.0063ms
maxEvenConjunction2 rezultat: 4094 trajanje 78.0045ms
maksimalni prag: 8192
maxEvenDividing rezultat: 8190 trajanje 107.0062ms
maxEvenDividing2 rezultat: 8190 trajanje 77.0044ms
maxEvenConjunction rezultat: 8190 trajanje 111.0063ms
maxEvenConjunction2 rezultat: 8190 trajanje 77.0044ms
max threshold: 16384
maxEvenDividing rezultat: 16382 trajanje 109.0063ms
maxEvenDividing2 rezultat: 16382 trajanje 77.0044ms
maxEvenConjunction rezultat: 16382 trajanje 108.0062ms
maxEvenConjunction2 rezultat: 16382 trajanje 77.0044ms
maksimalni prag: 32768
maxEvenDividing rezultat: 32766 trajanje 112.0064ms
maxEvenDividing2 rezultat: 32766 trajanje 77.0044ms
maxEvenConjunction rezultat: 32766 trajanje 109.0062ms
maxEvenConjunction2 rezultat: 32766 trajanje 78.0045ms
maksimalni prag: 65536
maxEvenDividing rezultat: 65534 trajanje 109.0062ms
maxEvenDividing2 rezultat: 65534 trajanje 75.0043ms
maxEvenConjunction rezultat: 65534 trajanje 109.0063ms
maxEvenConjunction2 rezultat: 65534 trajanje 79.0045ms
maksimalni prag: 131072
maxEvenDividing rezultat: 131070 trajanje 108.0061ms
maxEvenDividing2 rezultat: 131070 trajanje 76.0044ms
maxEvenConjunction rezultat: 131070 trajanje 110.0063ms
maxEvenConjunction2 rezultat: 131070 trajanje 80.0046ms
maksimalni prag: 262144
maxEvenDividing rezultat: 262142 trajanje 110.0063ms
maxEvenDividing2 rezultat: 262142 trajanje 76.0044ms
maxEvenConjunction rezultat: 262142 trajanje 107.0061ms
maxEvenConjunction2 rezultat: 262142 trajanje 78.0044ms
maksimalni prag: 524288
maxEvenDividing rezultat: 524286 trajanje 109.0062ms
maxEvenDividing2 rezultat: 524286 trajanje 78.0045ms
maxEvenConjunction rezultat: 524286 trajanje 109.0062ms
maxEvenConjunction2 rezultat: 524286 trajanje 80.0046ms
maksimalni prag: 1048576
maxEvenDividing rezultat: 1048574 trajanje 109.0063ms
maxEvenDividing2 rezultat: 1048574 trajanje 80.0045ms
maxEvenConjunction rezultat: 1048574 trajanje 114.0066ms
maxEvenConjunction2 rezultat: 1048574 trajanje 78.0044ms
maksimalni prag: 2097152
maxEvenDividing rezultat: 2097150 trajanje 111.0064ms
maxEvenDividing2 rezultat: 2097150 trajanje 79.0045ms
maxEvenConjunction rezultat: 2097150 trajanje 112.0064ms
maxEvenConjunction2 rezultat: 2097150 trajanje 77.0044ms
maksimalni prag: 4194304
maxEvenDividing rezultat: 4194302 trajanje 111.0063ms
maxEvenDividing2 rezultat: 4194302 trajanje 78.0045ms
maxEvenConjunction rezultat: 4194302 trajanje 111.0063ms
maxEvenConjunction2 rezultat: 4194302 trajanje 77.0044ms
max threshold: 8388608
maxEvenDividing rezultat: 8388606 trajanje 109.0062ms
maxEvenDividing2 rezultat: 8388606 trajanje 78.0045ms
maxEvenConjunction rezultat: 8388606 trajanje 114.0065ms
maxEvenConjunction2 rezultat: 8388606 trajanje 78.0045ms
maksimalni prag: 16777216
maxEvenDividing rezultat: 16777214 trajanje 109.0062ms
maxEvenDividing2 rezultat: 16777214 trajanje 77.0044ms
maxEvenConjunction rezultat: 16777214 trajanje 109.0063ms
maxEvenConjunction2 rezultat: 16777214 trajanje 77.0044ms
maksimalni prag: 33554432
maxEvenDividing rezultat: 33554430 trajanje 113.0065ms
maxEvenDividing2 rezultat: 33554430 trajanje 78.0045ms
maxEvenConjunction rezultat: 33554430 trajanje 110.0063ms
maxEvenConjunction2 rezultat: 33554430 trajanje 80.0045ms
maksimalni prag: 67108864
maxEvenDividing rezultat: 67108860 trajanje 112.0064ms
maxEvenDividing2 rezultat: 67108860 trajanje 77.0044ms
maxEvenConjunction rezultat: 67108860 trajanje 112.0064ms
maxEvenConjunction2 rezultat: 67108860 trajanje 80.0046ms
maksimalni prag: 134217728
maxEvenDividing rezultat: 134217726 trajanje 109.0063ms
maxEvenDividing2 rezultat: 134217726 trajanje 78.0044ms
maxEvenConjunction rezultat: 134217726 trajanje 114.0065ms
maxEvenConjunction2 rezultat: 134217726 trajanje 81.0047ms
maksimalni prag: 268435456
maxEvenDividing rezultat: 268435446 trajanje 111.0064ms
maxEvenDividing2 rezultat: 268435446 trajanje 79.0045ms
maxEvenConjunction rezultat: 268435446 trajanje 114.0065ms
maxEvenConjunction2 rezultat: 268435446 trajanje 79.0045ms
maksimalni prag: 536870912
maxEvenDividing rezultat: 536870910 trajanje 107.0062ms
maxEvenDividing2 rezultat: 536870910 trajanje 76.0043ms
maxEvenConjunction rezultat: 536870910 trajanje 109.0062ms
maxEvenConjunction2 rezultat: 536870910 trajanje 80.0046ms
Nisam našao jasnog objašnjenja zašto Go kompajler ne optimizira kod i uvijek provjerava drugu uvjet, čak i ako je prvi netočan — možda su mi se oči "smanjile" i ne vidim neku očitu grešku? Ili treba navesti neke posebne instrukcije za kompajler? Bio bih zahvalan na razumljivim komentarima.
PS: Da, iz radoznalosti, izveo sam slične testove na Javi 5 i Javi 7/8 — sve je jasno, vrijeme izvršavanja je isto.
Izvor: habr.com
