Betingelser i Go og deres merkeligheter

Hva mener du, er disse to alternativene for betingelsessjekk i løkken likestilte når det gjelder ytelse?

		
if a > b && c*2 > d {
	....
}
// og
if a  d {
 ....
}


Alt begynte med en 'oppvarming for hjernen', det var nødvendig å gi et eksempel på optimal søking i et array av heltall [-x….x] for det største partallet. Jeg ble nysgjerrig på hvor mye ytelsen ville øke dersom vi brukte logisk multiplikasjon med 1 for å avgjøre om tallet er partall.


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

Min erfaring med programmering i Go er ikke så stor, litt over ett og et halvt år, jeg har brukt det ganske ofte, men mest på utilitaristiske måter (kanskje unntatt ett prosjekt relatert til en høybelastet http-tjeneste), derfor begynte jeg nettopp med det. La oss åpne GoLand og skrive en enkel 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
        // Vi vil variere tallet fra minimum 
        // til maksimum. Jo mindre rekkevidde, desto mer 
        // prosessortid vil bli brukt på operasjonen 
        // for å sammenligne det nåværende tallet med det tidligere funnet og omvendt
	for maxValue = 128; maxValue  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
}

Vi får et resultat som viser at jo høyere terskel, desto mer fluktuasjoner i forhold til ytelsen forekommer.

Sammenlignmaks grense: 128
maksEvenDeling resultat: 126 varighet 116.0067ms
maksEvenSammenkobling resultat: 126 varighet 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 resultat: 8388606 varighet 109.0062ms

maks grense: 16777216
maxEvenDividing resultat: 16777214 varighet 108.0062ms
maxEvenConjunction resultat: 16777214 varighet 109.0062ms

maks grense: 33554432
maxEvenDividing resultat: 33554430 varighet 114.0066ms
maxEvenConjunction resultat: 33554430 varighet 110.0063ms

maks grense: 67108864
maxEvenDividing resultat: 67108860 varighet 111.0064ms
maxEvenConjunction resultat: 67108860 varighet 109.0062ms

maks grense: 134217728
maxEvenDividing resultat: 134217726 varighet 108.0062ms
maxEvenConjunction resultat: 134217726 varighet 109.0063ms

maks grense: 268435456
maxEvenDividing resultat: 268435446 varighet 111.0063ms
maxEvenConjunction resultat: 268435446 varighet 110.0063ms

Det er klart at for forskjellige grenser har vi forskjellige sett testdata, prosessorbelastningen (på min laptop i5-2540M) varierer mellom 20..30%, minnet som brukes av programmet som kjører fra GoLand er i gjennomsnitt rundt 813MB — dette påvirker også resultatets pålitelighet, det er nødvendig å implementere lagring av testsettene på disken og kjøre alle tester for hver grense isolert fra hverandre.

Og når jeg tenker på hvordan jeg kan implementere alt dette med minimale kostnader, retter jeg mekanisk betingelsessjekken.

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

En funksjon har blitt

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

jeg kjører testene en gang til… og mister helt oversikten 🙂

Tiden brukt på utføring begynner å avvike ikke med prosent/del av prosent, men med 10..15% Jeg skriver raskt to tester til:

		
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
}

jeg kjører og får opp dette bildet:initial array kapasitet: 100000000

maks grense: 128
maxEvenDividing resultat: 126 varighet 116.0066ms
maxEvenDividing2 resultat: 126 varighet 79.0045ms
maxEvenConjunction resultat: 126 varighet 114.0065ms
maxEvenConjunction2 resultat: 126 varighet 83.0048ms

maks grense: 256
maxEvenDividing resultat: 254 varighet 111.0063ms
maxEvenDividing2 resultat: 254 varighet 77.0044ms
maxEvenConjunction resultat: 254 varighet 110.0063ms
maxEvenConjunction2 resultat: 254 varighet 80.0046ms

maks grense: 512
maxEvenDividing resultat: 510 varighet 114.0066ms
maxEvenDividing2 resultat: 510 varighet 80.0045ms
maxEvenConjunction resultat: 510 varighet 110.0063ms
maxEvenConjunction2 resultat: 510 varighet 80.0046ms

maks grense: 1024
maxEvenDividing resultat: 1022 varighet 109.0063ms
maxEvenDividing2 resultat: 1022 varighet 77.0044ms
maxEvenConjunction resultat: 1022 varighet 111.0063ms
maxEvenConjunction2 resultat: 1022 varighet 81.0047ms

maks grense: 2048
maxEvenDividing resultat: 2046 varighet 114.0065ms
maxEvenDividing2 resultat: 2046 varighet 79.0045ms
maxEvenConjunction resultat: 2046 varighet 113.0065ms
maxEvenConjunction2 resultat: 2046 varighet 81.0046ms

maks grense: 4096
maxEvenDividing resultat: 4094 varighet 114.0065ms
maxEvenDividing2 resultat: 4094 varighet 80.0046ms
maxEvenConjunction resultat: 4094 varighet 111.0063ms
maxEvenConjunction2 resultat: 4094 varighet 78.0045ms

maks grense: 8192
maxEvenDividing resultat: 8190 varighet 107.0062ms
maxEvenDividing2 resultat: 8190 varighet 77.0044ms
maxEvenConjunction resultat: 8190 varighet 111.0063ms
maxEvenConjunction2 resultat: 8190 varighet 77.0044ms

max threshold: 16384
maxEvenDividing resultat: 16382 varighet 109.0063ms
maxEvenDividing2 resultat: 16382 varighet 77.0044ms
maxEvenConjunction resultat: 16382 varighet 108.0062ms
maxEvenConjunction2 resultat: 16382 varighet 77.0044ms

maks grense: 32768
maxEvenDividing resultat: 32766 varighet 112.0064ms
maxEvenDividing2 resultat: 32766 varighet 77.0044ms
maxEvenConjunction resultat: 32766 varighet 109.0062ms
maxEvenConjunction2 resultat: 32766 varighet 78.0045ms

maks grense: 65536
maxEvenDividing resultat: 65534 varighet 109.0062ms
maxEvenDividing2 resultat: 65534 varighet 75.0043ms
maxEvenConjunction resultat: 65534 varighet 109.0063ms
maxEvenConjunction2 resultat: 65534 varighet 79.0045ms

maks grense: 131072
maxEvenDividing resultat: 131070 varighet 108.0061ms
maxEvenDividing2 resultat: 131070 varighet 76.0044ms
maxEvenConjunction resultat: 131070 varighet 110.0063ms
maxEvenConjunction2 resultat: 131070 varighet 80.0046ms

maks grense: 262144
maxEvenDividing resultat: 262142 varighet 110.0063ms
maxEvenDividing2 resultat: 262142 varighet 76.0044ms
maxEvenConjunction resultat: 262142 varighet 107.0061ms
maxEvenConjunction2 resultat: 262142 varighet 78.0044ms

maks grense: 524288
maxEvenDividing resultat: 524286 varighet 109.0062ms
maxEvenDividing2 resultat: 524286 varighet 78.0045ms
maxEvenConjunction resultat: 524286 varighet 109.0062ms
maxEvenConjunction2 resultat: 524286 varighet 80.0046ms

maks grense: 1048576
maxEvenDividing resultat: 1048574 varighet 109.0063ms
maxEvenDividing2 resultat: 1048574 varighet 80.0045ms
maxEvenConjunction resultat: 1048574 varighet 114.0066ms
maxEvenConjunction2 resultat: 1048574 varighet 78.0044ms

maks grense: 2097152
maxEvenDividing resultat: 2097150 varighet 111.0064ms
maxEvenDividing2 resultat: 2097150 varighet 79.0045ms
maxEvenConjunction resultat: 2097150 varighet 112.0064ms
maxEvenConjunction2 resultat: 2097150 varighet 77.0044ms

maks grense: 4194304
maxEvenDividing resultat: 4194302 varighet 111.0063ms
maxEvenDividing2 resultat: 4194302 varighet 78.0045ms
maxEvenConjunction resultat: 4194302 varighet 111.0063ms
maxEvenConjunction2 resultat: 4194302 varighet 77.0044ms

max threshold: 8388608
maxEvenDividing resultat: 8388606 varighet 109.0062ms
maxEvenDividing2 resultat: 8388606 varighet 78.0045ms
maxEvenConjunction resultat: 8388606 varighet 114.0065ms
maxEvenConjunction2 resultat: 8388606 varighet 78.0045ms

maks grense: 16777216
maxEvenDividing resultat: 16777214 varighet 109.0062ms
maxEvenDividing2 resultat: 16777214 varighet 77.0044ms
maxEvenConjunction resultat: 16777214 varighet 109.0063ms
maxEvenConjunction2 resultat: 16777214 varighet 77.0044ms

maks grense: 33554432
maxEvenDividing resultat: 33554430 varighet 113.0065ms
maxEvenDividing2 resultat: 33554430 varighet 78.0045ms
maxEvenConjunction resultat: 33554430 varighet 110.0063ms
maxEvenConjunction2 resultat: 33554430 varighet 80.0045ms

maks grense: 67108864
maxEvenDividing resultat: 67108860 varighet 112.0064ms
maxEvenDividing2 resultat: 67108860 varighet 77.0044ms
maxEvenConjunction resultat: 67108860 varighet 112.0064ms
maxEvenConjunction2 resultat: 67108860 varighet 80.0046ms

maks grense: 134217728
maxEvenDividing resultat: 134217726 varighet 109.0063ms
maxEvenDividing2 resultat: 134217726 varighet 78.0044ms
maxEvenConjunction resultat: 134217726 varighet 114.0065ms
maxEvenConjunction2 resultat: 134217726 varighet 81.0047ms

maks grense: 268435456
maxEvenDividing resultat: 268435446 varighet 111.0064ms
maxEvenDividing2 resultat: 268435446 varighet 79.0045ms
maxEvenConjunction resultat: 268435446 varighet 114.0065ms
maxEvenConjunction2 resultat: 268435446 varighet 79.0045ms

maks grense: 536870912
maxEvenDividing resultat: 536870910 varighet 107.0062ms
maxEvenDividing2 resultat: 536870910 varighet 76.0043ms
maxEvenConjunction result: 536870910 duration 109.0062ms
maxEvenConjunction2 result: 536870910 duration 80.0046ms

Eg entydelig forklaring på hvorfor Go-kompilatoren ikke optimaliserer koden og alltid sjekker det andre vilkåret, selv om det første er usant — har jeg ikke funnet. Kanskje er øynene mine bare blitt 'sløret', og jeg ser ikke en åpenbar feil? Eller må jeg spesifisere noen spesielle instruksjoner til kompilatoren? Jeg ville satt pris på fornuftige kommentarer.

PS: Ja, for moro skyld, kjørte jeg lignende tester på Java 5 og Java 7/8 — alt gikk fint, kjøretiden var den samme.

Kilde: habr.com

Kjøp pålitelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere 🔥 Kjøp pålitelig hosting for nettsteder med DDoS-beskyttelse, VPS VDS-servere | ProHoster