Betingelser i Go og deres underligheder

Hvad mener du, er disse to betingelseskontrolmuligheder i en løkke ækvivalente i ydelse?

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


Det hele startede med en "opvarmning for hjernen", hvor jeg skulle give et eksempel på optimal søgning i et array af heltal [-x….x] for det største lige tal. Jeg blev nysgerrig på, hvor meget bedre ydelsen ville være, hvis man i stedet for at finde ud af, om et tal er lige, brugte logisk multiplikation med 1.


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

Min erfaring med Go er ikke særlig stor, lidt over halvandet år, selvom jeg ofte har brugt det, var det primært til utility-områder (måske undtagen ét projekt relateret til en højtydende http-service), derfor begyndte jeg netop med det. Lad os åbne GoLand og skrive en simpel 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 antallet af tal fra det minimum 
	// til maksimum. Jo mindre området er, desto mere 
	// proces tid vil gå til operativsystemet 
	// sammenligning af det aktuelle tal med det tidligere fundet 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, hvor det er tydeligt, at jo større threshold, desto oftere forekommer der fluktuationer i ydelse.

Sammenlignmaksimalt tærskel: 128
maxEvenDividing resultat: 126 varighed 116.0067ms
maxEvenConjunction resultat: 126 varighed 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 varighed 109.0062ms

maksimum tærskel: 16777216
maxEvenDividing resultat: 16777214 varighed 108.0062ms
maxEvenConjunction resultat: 16777214 varighed 109.0062ms

maksimum tærskel: 33554432
maxEvenDividing resultat: 33554430 varighed 114.0066ms
maxEvenConjunction resultat: 33554430 varighed 110.0063ms

maksimum tærskel: 67108864
maxEvenDividing resultat: 67108860 varighed 111.0064ms
maxEvenConjunction resultat: 67108860 varighed 109.0062ms

maksimum tærskel: 134217728
maxEvenDividing resultat: 134217726 varighed 108.0062ms
maxEvenConjunction resultat: 134217726 varighed 109.0063ms

maksimum tærskel: 268435456
maxEvenDividing resultat: 268435446 varighed 111.0063ms
maxEvenConjunction resultat: 268435446 varighed 110.0063ms

Det er klart, at vi i dette tilfælde har forskellige sæt testdata for forskellige tærskler, CPU-belastningen (på min bærbare i5-2540M) varierer omkring 20..30%, og den hukommelse, der bruges af applikationen kørt fra GoLand er i gennemsnit omkring 813MB - dette påvirker også pålideligheden af resultatet, vi skal implementere gemning af testsæt på disken og køre alle tests for hver tærskel isoleret fra hinanden.

Og når jeg overvejer, hvordan jeg med minimal omkostning kan implementere alt dette, retter jeg automatisk betingelseskontrollen.

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

og få en fungerende kommando.

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

jeg kører testene endnu en gang… og stopper med at forstå noget 🙂

Den tid, der bruges til udførelsen, begynder at afvige, ikke kun med procentdele, men med 10..15%. Jeg skriver hurtigt 2 ekstra test:

		
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 kører og får lige præcis dette billede:initial array kapacitet: 100000000

maksimalt tærskel: 128
maxEvenDividing resultat: 126 varighed 116.0066ms
maxEvenDividing2 resultat: 126 varighed 79.0045ms
maxEvenConjunction resultat: 126 varighed 114.0065ms
maxEvenConjunction2 resultat: 126 varighed 83.0048ms

maksimum tærskel: 256
maxEvenDividing resultat: 254 varighed 111.0063ms
maxEvenDividing2 resultat: 254 varighed 77.0044ms
maxEvenConjunction resultat: 254 varighed 110.0063ms
maxEvenConjunction2 resultat: 254 varighed 80.0046ms

maksimum tærskel: 512
maxEvenDividing resultat: 510 varighed 114.0066ms
maxEvenDividing2 resultat: 510 varighed 80.0045ms
maxEvenConjunction resultat: 510 varighed 110.0063ms
maxEvenConjunction2 resultat: 510 varighed 80.0046ms

maksimum tærskel: 1024
maxEvenDividing resultat: 1022 varighed 109.0063ms
maxEvenDividing2 resultat: 1022 varighed 77.0044ms
maxEvenConjunction resultat: 1022 varighed 111.0063ms
maxEvenConjunction2 resultat: 1022 varighed 81.0047ms

maksimum tærskel: 2048
maxEvenDividing resultat: 2046 varighed 114.0065ms
maxEvenDividing2 resultat: 2046 varighed 79.0045ms
maxEvenConjunction resultat: 2046 varighed 113.0065ms
maxEvenConjunction2 resultat: 2046 varighed 81.0046ms

maks grænse: 4096
maxEvenDividing resultat: 4094 varighed 114.0065ms
maxEvenDividing2 resultat: 4094 varighed 80.0046ms
maxEvenConjunction resultat: 4094 varighed 111.0063ms
maxEvenConjunction2 resultat: 4094 varighed 78.0045ms

maks grænse: 8192
maxEvenDividing resultat: 8190 varighed 107.0062ms
maxEvenDividing2 resultat: 8190 varighed 77.0044ms
maxEvenConjunction resultat: 8190 varighed 111.0063ms
maxEvenConjunction2 resultat: 8190 varighed 77.0044ms

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

maks grænse: 32768
maxEvenDividing resultat: 32766 varighed 112.0064ms
maxEvenDividing2 resultat: 32766 varighed 77.0044ms
maxEvenConjunction resultat: 32766 varighed 109.0062ms
maxEvenConjunction2 resultat: 32766 varighed 78.0045ms

maks grænse: 65536
maxEvenDividing resultat: 65534 varighed 109.0062ms
maxEvenDividing2 resultat: 65534 varighed 75.0043ms
maxEvenConjunction resultat: 65534 varighed 109.0063ms
maxEvenConjunction2 resultat: 65534 varighed 79.0045ms

maks grænse: 131072
maxEvenDividing resultat: 131070 varighed 108.0061ms
maxEvenDividing2 resultat: 131070 varighed 76.0044ms
maxEvenConjunction resultat: 131070 varighed 110.0063ms
maxEvenConjunction2 resultat: 131070 varighed 80.0046ms

maks grænse: 262144
maxEvenDividing resultat: 262142 varighed 110.0063ms
maxEvenDividing2 resultat: 262142 varighed 76.0044ms
maxEvenConjunction resultat: 262142 varighed 107.0061ms
maxEvenConjunction2 resultat: 262142 varighed 78.0044ms

maks grænse: 524288
maxEvenDividing resultat: 524286 varighed 109.0062ms
maxEvenDividing2 resultat: 524286 varighed 78.0045ms
maxEvenConjunction resultat: 524286 varighed 109.0062ms
maxEvenConjunction2 resultat: 524286 varighed 80.0046ms

maks grænse: 1048576
maxEvenDividing resultat: 1048574 varighed 109.0063ms
maxEvenDividing2 resultat: 1048574 varighed 80.0045ms
maxEvenConjunction resultat: 1048574 varighed 114.0066ms
maxEvenConjunction2 resultat: 1048574 varighed 78.0044ms

maks grænse: 2097152
maxEvenDividing resultat: 2097150 varighed 111.0064ms
maxEvenDividing2 resultat: 2097150 varighed 79.0045ms
maxEvenConjunction resultat: 2097150 varighed 112.0064ms
maxEvenConjunction2 resultat: 2097150 varighed 77.0044ms

maks grænse: 4194304
maxEvenDividing resultat: 4194302 varighed 111.0063ms
maxEvenDividing2 resultat: 4194302 varighed 78.0045ms
maxEvenConjunction resultat: 4194302 varighed 111.0063ms
maxEvenConjunction2 resultat: 4194302 varighed 77.0044ms

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

maksimum tærskel: 16777216
maxEvenDividing resultat: 16777214 varighed 109.0062ms
maxEvenDividing2 resultat: 16777214 varighed 77.0044ms
maxEvenConjunction resultat: 16777214 varighed 109.0063ms
maxEvenConjunction2 resultat: 16777214 varighed 77.0044ms

maksimum tærskel: 33554432
maxEvenDividing resultat: 33554430 varighed 113.0065ms
maxEvenDividing2 resultat: 33554430 varighed 78.0045ms
maxEvenConjunction resultat: 33554430 varighed 110.0063ms
maxEvenConjunction2 resultat: 33554430 varighed 80.0045ms

maksimum tærskel: 67108864
maxEvenDividing resultat: 67108860 varighed 112.0064ms
maxEvenDividing2 resultat: 67108860 varighed 77.0044ms
maxEvenConjunction resultat: 67108860 varighed 112.0064ms
maxEvenConjunction2 resultat: 67108860 varighed 80.0046ms

maksimum tærskel: 134217728
maxEvenDividing resultat: 134217726 varighed 109.0063ms
maxEvenDividing2 resultat: 134217726 varighed 78.0044ms
maxEvenConjunction resultat: 134217726 varighed 114.0065ms
maxEvenConjunction2 resultat: 134217726 varighed 81.0047ms

maksimum tærskel: 268435456
maxEvenDividing resultat: 268435446 varighed 111.0064ms
maxEvenDividing2 resultat: 268435446 varighed 79.0045ms
maxEvenConjunction resultat: 268435446 varighed 114.0065ms
maxEvenConjunction2 resultat: 268435446 varighed 79.0045ms

maks grænse: 536870912
maxEvenDividing resultat: 536870910 varighed 107.0062ms
maxEvenDividing2 resultat: 536870910 varighed 76.0043ms
maxEvenConjunction resultat: 536870910 varighed 109.0062ms
maxEvenConjunction2 resultat: 536870910 varighed 80.0046ms

Jeg fandt ikke noget klart forklaring på, hvorfor Go-kompilatoren ikke optimerer koden og altid kontrollerer den anden betingelse, selvom den første er falsk - måske har jeg bare haft for travlt og ikke kan se en åbenlys fejl? Måske skal jeg give kompilatoren nogle særlige instruktioner? Jeg ville sætte pris på nogle nyttige kommentarer.

PS: Ja, for sjov skyld kørte jeg lignende tests på Java 5 og Java 7/8 - alt var klart, udførelsestiden var den samme.

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster