Olosuhteet Gossa ja niiden omituisuudet

Ovatko nämä kaksi vaihtoehtoa silmukan sisäisten olosuhteiden testaamiseksi mielestäsi suorituskyvyltään samanlaisia?

		
if a > b && c*2 > d {
	....
}
// и
if a <= b  { 
  continue;
}
if c*2 > d {
 ....
}


Kaikki alkoi "aivojen lämmittelystä"; minun piti antaa esimerkki optimaalisesta hausta suurimmalle parilliselle luvulle kokonaislukujoukosta [-x....x]. Mietin, kuinka paljon parempi suorituskyky olisi, jos käyttäisin loogista kertolaskua yhdellä selvittääkseni, onko luku parillinen vai ei.


//у четных чисел последний бит всегда равен 0
value & 1 == 0
//vs классический метод
value % 2 == 0

Ohjelmointikokemukseni Gossa ei ole kovin laaja, hieman yli puolitoista vuotta, käytin sitä, vaikkakin usein, mutta puhtaasti utilitaristisiin tarkoituksiin (no, ehkä paitsi yhtä projektia, joka liittyy paljon kuormitettuun http-palveluun), joten aloitti sillä. Avaa GoLand ja kirjoita yksinkertainen testi


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
        // Будем варьировать диапазон чисел от минимального 
        // до максимального. Чем меньше диапазон, тем больше 
        // процессорного времени будет уходить на операцию 
        // сравнения текущего числа, с ранее найденным и наоборот
	for maxValue = 128; maxValue < math.MaxInt32/2+1; maxValue = maxValue * 2 {
		test(maxValue)
	}
}

func test(maxValue int32) {
	log.Println("max threshold: " + fmt.Sprint(maxValue))
	arr := make([]int32, size)
	for i := range arr {
		arr[i] = rand.Int31n(maxValue)
                // в тестовых данных нам нужны и отрицательные числа 
		sign := rand.Intn(2)
		if sign == 1 {
			arr[i] = -arr[i]
		}
	}

        // запускаем тест "деление с остатком"
	result := maxEvenDividing("maxEvenDividing", arr)
	log.Printf(result.Name+"t result: "+fmt.Sprint(result.Value)+"ttduration %s", result.Duration)

        // запускаем тест "конъюнкции"
	result = maxEvenConjunction("maxEvenConjunction", arr)
	log.Printf(result.Name+"t result: "+fmt.Sprint(result.Value)+"ttduration %s", result.Duration)
}

func maxEvenDividing(name string, arr []int32) Result {
	start := time.Now()
	var current int32 = math.MinInt32
	for _, value := range arr {
		if value > current && value%2 == 0 {
			current = value
		}
	}
	duration := time.Since(start)
	result := Result{name, duration, current}
	return result
}

func maxEvenConjunction(name string, arr []int32) Result {
	start := time.Now()
	var current int32 = math.MinInt32
	for _, value := range arr {
		if value > current && value&1 == 0 {
			current = value
		}
	}
	duration := time.Since(start)
	result := Result{name, duration, current}
	return result
}

Saamme tuloksen, joka osoittaa, että mitä korkeampi kynnys on, sitä useammin suorituskyvyn vaihtelut näkyvät.

vertaillamax threshold: 128
maxEvenDividing result: 126 duration 116.0067ms
maxEvenConjunction result: 126 duration 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 result: 8388606 duration 109.0062ms

max threshold: 16777216
maxEvenDividing result: 16777214 duration 108.0062ms
maxEvenConjunction result: 16777214 duration 109.0062ms

max threshold: 33554432
maxEvenDividing result: 33554430 duration 114.0066ms
maxEvenConjunction result: 33554430 duration 110.0063ms

max threshold: 67108864
maxEvenDividing result: 67108860 duration 111.0064ms
maxEvenConjunction result: 67108860 duration 109.0062ms

max threshold: 134217728
maxEvenDividing result: 134217726 duration 108.0062ms
maxEvenConjunction result: 134217726 duration 109.0063ms

max threshold: 268435456
maxEvenDividing result: 268435446 duration 111.0063ms
maxEvenConjunction result: 268435446 duration 110.0063ms

On selvää, että tässä tapauksessa eri kynnyksillä meillä on erilaisia ​​testidatajoukkoja, prosessorin kuormitus (i5-2540M kannettavassa tietokoneessani) vaihtelee noin 20..30%, GoLandista toimivan sovelluksen käyttämä muisti on keskimäärin. noin 813 Mt - tämä vaikuttaa myös tuloksen luotettavuuteen, sinun on tallennettava testitapaukset levylle ja suoritettava kaikki testit jokaiselle kynnysarvolle erillään toisistaan.

Ja nyt, kun mietin, kuinka tämä kaikki toteutetaan pienin kustannuksin, korjaan automaattisesti kuntotarkastuksen

		
if value > current && value&1 == 0 {
	current = value
}

päälle

		
if value <= current {
        continue;
}
if value&1 == 0 {
	current = value
}

Teen testit uudestaan... enkä ymmärrä mitään :)

Suoritukseen käytetty aika alkaa poiketa ei enää prosenttiosuuksilla/prosentin murto-osilla, vaan 10...15%. Lisään nopeasti vielä 2 testiä:

		
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
}

Suoritan sen ja saan tämän kuvan:Alkuperäinen kapasiteetti: 100000000

enimmäisraja: 128
maxEvenJakotulos: 126 kesto 116.0066ms
maxEvenDividing2 tulos: 126 kesto 79.0045ms
maxEvenConjunction tulos: 126 kesto 114.0065 ms
maxEvenConjunction2 tulos: 126 kesto 83.0048ms

enimmäisraja: 256
maxEvenJakotulos: 254 kesto 111.0063ms
maxEvenDividing2 tulos: 254 kesto 77.0044ms
maxEvenConjunction tulos: 254 kesto 110.0063 ms
maxEvenConjunction2 tulos: 254 kesto 80.0046ms

enimmäisraja: 512
maxEvenJakotulos: 510 kesto 114.0066ms
maxEvenDividing2 tulos: 510 kesto 80.0045ms
maxEvenConjunction tulos: 510 kesto 110.0063 ms
maxEvenConjunction2 tulos: 510 kesto 80.0046ms

enimmäisraja: 1024
maxEvenJakotulos: 1022 kesto 109.0063ms
maxEvenDividing2 tulos: 1022 kesto 77.0044ms
maxEvenConjunction tulos: 1022 kesto 111.0063 ms
maxEvenConjunction2 tulos: 1022 kesto 81.0047ms

enimmäisraja: 2048
maxEvenJakotulos: 2046 kesto 114.0065ms
maxEvenDividing2 tulos: 2046 kesto 79.0045ms
maxEvenConjunction tulos: 2046 kesto 113.0065 ms
maxEvenConjunction2 tulos: 2046 kesto 81.0046ms

enimmäisraja: 4096
maxEvenJakotulos: 4094 kesto 114.0065ms
maxEvenDividing2 tulos: 4094 kesto 80.0046ms
maxEvenConjunction tulos: 4094 kesto 111.0063 ms
maxEvenConjunction2 tulos: 4094 kesto 78.0045ms

enimmäisraja: 8192
maxEvenJakotulos: 8190 kesto 107.0062ms
maxEvenDividing2 tulos: 8190 kesto 77.0044ms
maxEvenConjunction tulos: 8190 kesto 111.0063 ms
maxEvenConjunction2 tulos: 8190 kesto 77.0044ms

enimmäisraja: 16384
maxEvenJakotulos: 16382 kesto 109.0063ms
maxEvenDividing2 tulos: 16382 kesto 77.0044ms
maxEvenConjunction tulos: 16382 kesto 108.0062 ms
maxEvenConjunction2 tulos: 16382 kesto 77.0044ms

enimmäisraja: 32768
maxEvenJakotulos: 32766 kesto 112.0064ms
maxEvenDividing2 tulos: 32766 kesto 77.0044ms
maxEvenConjunction tulos: 32766 kesto 109.0062 ms
maxEvenConjunction2 tulos: 32766 kesto 78.0045ms

enimmäisraja: 65536
maxEvenJakotulos: 65534 kesto 109.0062ms
maxEvenDividing2 tulos: 65534 kesto 75.0043ms
maxEvenConjunction tulos: 65534 kesto 109.0063 ms
maxEvenConjunction2 tulos: 65534 kesto 79.0045ms

enimmäisraja: 131072
maxEvenJakotulos: 131070 kesto 108.0061ms
maxEvenDividing2 tulos: 131070 kesto 76.0044ms
maxEvenConjunction tulos: 131070 kesto 110.0063 ms
maxEvenConjunction2 tulos: 131070 kesto 80.0046ms

enimmäisraja: 262144
maxEvenJakotulos: 262142 kesto 110.0063ms
maxEvenDividing2 tulos: 262142 kesto 76.0044ms
maxEvenConjunction tulos: 262142 kesto 107.0061 ms
maxEvenConjunction2 tulos: 262142 kesto 78.0044ms

enimmäisraja: 524288
maxEvenJakotulos: 524286 kesto 109.0062ms
maxEvenDividing2 tulos: 524286 kesto 78.0045ms
maxEvenConjunction tulos: 524286 kesto 109.0062 ms
maxEvenConjunction2 tulos: 524286 kesto 80.0046ms

enimmäisraja: 1048576
maxEvenJakotulos: 1048574 kesto 109.0063ms
maxEvenDividing2 tulos: 1048574 kesto 80.0045ms
maxEvenConjunction tulos: 1048574 kesto 114.0066 ms
maxEvenConjunction2 tulos: 1048574 kesto 78.0044ms

enimmäisraja: 2097152
maxEvenJakotulos: 2097150 kesto 111.0064ms
maxEvenDividing2 tulos: 2097150 kesto 79.0045ms
maxEvenConjunction tulos: 2097150 kesto 112.0064 ms
maxEvenConjunction2 tulos: 2097150 kesto 77.0044ms

enimmäisraja: 4194304
maxEvenJakotulos: 4194302 kesto 111.0063ms
maxEvenDividing2 tulos: 4194302 kesto 78.0045ms
maxEvenConjunction tulos: 4194302 kesto 111.0063 ms
maxEvenConjunction2 tulos: 4194302 kesto 77.0044ms

enimmäisraja: 8388608
maxEvenJakotulos: 8388606 kesto 109.0062ms
maxEvenDividing2 tulos: 8388606 kesto 78.0045ms
maxEvenConjunction tulos: 8388606 kesto 114.0065 ms
maxEvenConjunction2 tulos: 8388606 kesto 78.0045ms

enimmäisraja: 16777216
maxEvenJakotulos: 16777214 kesto 109.0062ms
maxEvenDividing2 tulos: 16777214 kesto 77.0044ms
maxEvenConjunction tulos: 16777214 kesto 109.0063 ms
maxEvenConjunction2 tulos: 16777214 kesto 77.0044ms

enimmäisraja: 33554432
maxEvenJakotulos: 33554430 kesto 113.0065ms
maxEvenDividing2 tulos: 33554430 kesto 78.0045ms
maxEvenConjunction tulos: 33554430 kesto 110.0063 ms
maxEvenConjunction2 tulos: 33554430 kesto 80.0045ms

enimmäisraja: 67108864
maxEvenJakotulos: 67108860 kesto 112.0064ms
maxEvenDividing2 tulos: 67108860 kesto 77.0044ms
maxEvenConjunction tulos: 67108860 kesto 112.0064 ms
maxEvenConjunction2 tulos: 67108860 kesto 80.0046ms

enimmäisraja: 134217728
maxEvenJakotulos: 134217726 kesto 109.0063ms
maxEvenDividing2 tulos: 134217726 kesto 78.0044ms
maxEvenConjunction tulos: 134217726 kesto 114.0065 ms
maxEvenConjunction2 tulos: 134217726 kesto 81.0047ms

enimmäisraja: 268435456
maxEvenJakotulos: 268435446 kesto 111.0064ms
maxEvenDividing2 tulos: 268435446 kesto 79.0045ms
maxEvenConjunction tulos: 268435446 kesto 114.0065 ms
maxEvenConjunction2 tulos: 268435446 kesto 79.0045ms

enimmäisraja: 536870912
maxEvenJakotulos: 536870910 kesto 107.0062ms
maxEvenDividing2 tulos: 536870910 kesto 76.0043ms
maxEvenConjunction tulos: 536870910 kesto 109.0062 ms
maxEvenConjunction2 tulos: 536870910 kesto 80.0046ms

En löytänyt selkeää selitystä, miksi Go-kääntäjä ei optimoi koodia ja tarkistaa aina toisen ehdon, vaikka ensimmäinen olisi epätosi. Tai ehkä silmäni ovat vain sumeat enkä näe mitään selvää virhettä? Vai pitääkö kääntäjälle antaa erityisiä ohjeita? Olisin iloinen asiallisista kommenteista.

PS: Kyllä, huvin vuoksi suoritin samanlaisia ​​testejä Java 5:llä ja Java 7/8:lla - kaikki on selvää, suoritusaika on sama.

Lähde: will.com

Lisää kommentti