Kushtet në Go dhe çuditë e tyre

A mendoni, a janë ekuivalente këto dy metoda të kontrollit të kushteve brenda ciklit në performancë?

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


E gjithçka filloi me "ngrohje për trurin", duhej të jepja një shembull të kërkimit optimal në një masiv numrash të gjithëmbarësh [-x….x] për numrin më të madh çift. Më interesonte sa ishte më e lartë performanca nëse për të përcaktuar nëse një numër është çift, do të përdorej shumëzimi logjik me 1.


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

Eksperienca ime në programimin me Go nuk është shumë e madhe, pak më shumë se një vit e gjysmë, e kam përdorur shpesh, por kryesisht për qëllime utilitare (ndoshta përveç një projekti të lidhur me një shërbim http me ngarkesë të lartë), prandaj e fillova pikërisht me të. Hapim GoLand dhe shkruajmë një test të thjeshtë.


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("kapaciteti fillestar i masivit: " + fmt.Sprint(size))
	var maxValue int32
        // Do të variablim gamën e numrave nga minimalja 
        // deri në maksimale. Sa më i vogël gamën, aq më shumë 
        // koha e përpunimit do të shkojë në operacionin 
        // për krahasimin e numrit aktual me numrin e gjetur më parë
	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
}

Marrim rezultatin, në të cilin duket se sa më i lartë të jetë pragu, aq më shpesh shfaqen fluktuacione në performancë.

Krahasonipragu maksimal: 128
rezultati maxEvenDividing: 126 kohë 116.0067ms
rezultati maxEvenConjunction: 126 kohë 116.0066ms

pragu maksimal: 16384
rezultati maxEvenDividing: 16382 koha 115.0066ms
rezultati maxEvenConjunction: 16382 koha 111.0064ms

......

pragu maksimal: 8388608
rezultati maxEvenDividing: 8388606 koha 109.0063ms
rezultati maxEvenConjunction: 8388606 kohëzgjatja 109.0062ms

pragu maksimal: 16777216
rezultati maxEvenDividing: 16777214 kohëzgjatja 108.0062ms
rezultati maxEvenConjunction: 16777214 kohëzgjatja 109.0062ms

pragu maksimal: 33554432
rezultati maxEvenDividing: 33554430 kohëzgjatja 114.0066ms
rezultati maxEvenConjunction: 33554430 kohëzgjatja 110.0063ms

pragu maksimal: 67108864
rezultati maxEvenDividing: 67108860 kohëzgjatja 111.0064ms
rezultati maxEvenConjunction: 67108860 kohëzgjatja 109.0062ms

pragu maksimal: 134217728
rezultati maxEvenDividing: 134217726 kohëzgjatja 108.0062ms
rezultati maxEvenConjunction: 134217726 kohëzgjatja 109.0063ms

pragu maksimal: 268435456
rezultati maxEvenDividing: 268435446 kohëzgjatja 111.0063ms
rezultati maxEvenConjunction: 268435446 kohëzgjatja 110.0063ms

Është e qartë se në këtë rast, për pragje të ndryshme kemi grupe të ndryshme të të dhënave testuese, ngarkesa e procesorit (në laptopin tim i5-2540M) varion rreth 20..30%, memoria e zënë nga aplikacioni të cilin e kam ekzekutuar nga GoLand është rreth 813Mb — kjo gjithashtu ndikon në besueshmërinë e rezultatit, duhet të realizoj ruajtjen e grupeve të testit në disk dhe të ekzekutoj të gjitha testet për çdo prag të izoluar nga njëri-tjetri.

Dhe, duke menduar se si të realizoj gjithë këtë me minimale shpenzime, automatikisht e korrigjoj kontrollin e kushteve

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

në

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

ekzekutoj testet edhe një herë… dhe ndaloj së kuptuari gjithçka 🙂

Koha e harxhuar për ekzekutimin fillon të ndryshojë jo më në përqindje/pjesë të përqindjes, por në 10..15% Shpejt shkruaj edhe 2 teste të tjera:

		
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
}

ekzekutoj dhe marr një pamje të tillë:kapaciteti fillestar i array: 100000000

pragu maksimal: 128
rezultati maxEvenDividing: 126 kohëzgjatja 116.0066ms
rezultati maxEvenDividing2: 126 kohëzgjatja 79.0045ms
rezultati maxEvenConjunction: 126 kohëzgjatja 114.0065ms
rezultati maxEvenConjunction2: 126 kohëzgjatja 83.0048ms

pragu maksimal: 256
rezultati maxEvenDividing: 254 kohëzgjatja 111.0063ms
rezultati maxEvenDividing2: 254 kohëzgjatja 77.0044ms
rezultati maxEvenConjunction: 254 kohëzgjatja 110.0063ms
rezultati maxEvenConjunction2: 254 kohëzgjatja 80.0046ms

pragu maksimal: 512
rezultati maxEvenDividing: 510 kohëzgjatja 114.0066ms
rezultati maxEvenDividing2: 510 kohëzgjatja 80.0045ms
rezultati maxEvenConjunction: 510 kohëzgjatja 110.0063ms
rezultati maxEvenConjunction2: 510 kohëzgjatja 80.0046ms

pragu maksimal: 1024
rezultati maxEvenDividing: 1022 kohëzgjatja 109.0063ms
rezultati maxEvenDividing2: 1022 kohëzgjatja 77.0044ms
rezultati maxEvenConjunction: 1022 kohëzgjatja 111.0063ms
rezultati maxEvenConjunction2: 1022 kohëzgjatja 81.0047ms

pragu maksimal: 2048
rezultati maxEvenDividing: 2046 kohëzgjatja 114.0065ms
rezultati maxEvenDividing2: 2046 kohëzgjatja 79.0045ms
rezultati maxEvenConjunction: 2046 kohëzgjatja 113.0065ms
maxEvenConjunction2 rezultati: 2046 kohëzgjatja 81.0046ms

pragu maksimal: 4096
maxEvenDividing rezultati: 4094 kohëzgjatja 114.0065ms
maxEvenDividing2 rezultati: 4094 kohëzgjatja 80.0046ms
maxEvenConjunction rezultati: 4094 kohëzgjatja 111.0063ms
maxEvenConjunction2 rezultati: 4094 kohëzgjatja 78.0045ms

pragu maksimal: 8192
maxEvenDividing rezultati: 8190 kohëzgjatja 107.0062ms
maxEvenDividing2 rezultati: 8190 kohëzgjatja 77.0044ms
maxEvenConjunction rezultati: 8190 kohëzgjatja 111.0063ms
maxEvenConjunction2 rezultati: 8190 kohëzgjatja 77.0044ms

pragu maksimal: 16384
maxEvenDividing rezultati: 16382 kohëzgjatja 109.0063ms
maxEvenDividing2 rezultati: 16382 kohëzgjatja 77.0044ms
maxEvenConjunction rezultati: 16382 kohëzgjatja 108.0062ms
maxEvenConjunction2 rezultati: 16382 kohëzgjatja 77.0044ms

pragu maksimal: 32768
maxEvenDividing rezultati: 32766 kohëzgjatja 112.0064ms
maxEvenDividing2 rezultati: 32766 kohëzgjatja 77.0044ms
maxEvenConjunction rezultati: 32766 kohëzgjatja 109.0062ms
maxEvenConjunction2 rezultati: 32766 kohëzgjatja 78.0045ms

pragu maksimal: 65536
maxEvenDividing rezultati: 65534 kohëzgjatja 109.0062ms
maxEvenDividing2 rezultati: 65534 kohëzgjatja 75.0043ms
maxEvenConjunction rezultati: 65534 kohëzgjatja 109.0063ms
maxEvenConjunction2 rezultati: 65534 kohëzgjatja 79.0045ms

pragu maksimal: 131072
maxEvenDividing rezultati: 131070 kohëzgjatja 108.0061ms
maxEvenDividing2 rezultati: 131070 kohëzgjatja 76.0044ms
maxEvenConjunction rezultati: 131070 kohëzgjatja 110.0063ms
maxEvenConjunction2 rezultati: 131070 kohëzgjatja 80.0046ms

pragu maksimal: 262144
maxEvenDividing rezultati: 262142 kohëzgjatja 110.0063ms
maxEvenDividing2 rezultati: 262142 kohëzgjatja 76.0044ms
maxEvenConjunction rezultati: 262142 kohëzgjatja 107.0061ms
maxEvenConjunction2 rezultati: 262142 kohëzgjatja 78.0044ms

pragu maksimal: 524288
maxEvenDividing rezultati: 524286 kohëzgjatja 109.0062ms
maxEvenDividing2 rezultati: 524286 kohëzgjatja 78.0045ms
maxEvenConjunction rezultati: 524286 kohëzgjatja 109.0062ms
maxEvenConjunction2 rezultati: 524286 kohëzgjatja 80.0046ms

pragu maksimal: 1048576
maxEvenDividing rezultati: 1048574 kohëzgjatja 109.0063ms
maxEvenDividing2 rezultati: 1048574 kohëzgjatja 80.0045ms
maxEvenConjunction rezultati: 1048574 kohëzgjatja 114.0066ms
maxEvenConjunction2 rezultati: 1048574 kohëzgjatja 78.0044ms

pragu maksimal: 2097152
maxEvenDividing rezultati: 2097150 kohëzgjatja 111.0064ms
maxEvenDividing2 rezultati: 2097150 kohëzgjatja 79.0045ms
maxEvenConjunction rezultati: 2097150 kohëzgjatja 112.0064ms
maxEvenConjunction2 rezultati: 2097150 kohëzgjatja 77.0044ms

pragu maksimal: 4194304
maxEvenDividing rezultati: 4194302 kohëzgjatja 111.0063ms
maxEvenDividing2 rezultati: 4194302 kohëzgjatja 78.0045ms
maxEvenConjunction rezultati: 4194302 kohëzgjatja 111.0063ms
maxEvenConjunction2 rezultati: 4194302 kohëzgjatja 77.0044ms

pragu maksimal: 8388608
maxEvenDividing rezultati: 8388606 kohëzgjatja 109.0062ms
maxEvenDividing2 rezultati: 8388606 kohëzgjatja 78.0045ms
maxEvenConjunction rezultati: 8388606 kohëzgjatja 114.0065ms
maxEvenConjunction2 rezultati: 8388606 kohëzgjatja 78.0045ms

pragu maksimal: 16777216
maxEvenDividing rezultati: 16777214 kohëzgjatja 109.0062ms
maxEvenDividing2 rezultati: 16777214 kohëzgjatja 77.0044ms
maxEvenConjunction rezultati: 16777214 kohëzgjatja 109.0063ms
maxEvenConjunction2 rezultati: 16777214 kohëzgjatja 77.0044ms

pragu maksimal: 33554432
maxEvenDividing rezultati: 33554430 kohëzgjatja 113.0065ms
maxEvenDividing2 rezultati: 33554430 kohëzgjatja 78.0045ms
rezultati maxEvenConjunction: 33554430 kohëzgjatja 110.0063ms
maxEvenConjunction2 rezultati: 33554430 kohëzgjatja 80.0045ms

pragu maksimal: 67108864
maxEvenDividing rezultati: 67108860 kohëzgjatja 112.0064ms
maxEvenDividing2 rezultati: 67108860 kohëzgjatja 77.0044ms
maxEvenConjunction rezultati: 67108860 kohëzgjatja 112.0064ms
maxEvenConjunction2 rezultati: 67108860 kohëzgjatja 80.0046ms

pragu maksimal: 134217728
maxEvenDividing rezultati: 134217726 kohëzgjatja 109.0063ms
maxEvenDividing2 rezultati: 134217726 kohëzgjatja 78.0044ms
maxEvenConjunction rezultati: 134217726 kohëzgjatja 114.0065ms
maxEvenConjunction2 rezultati: 134217726 kohëzgjatja 81.0047ms

pragu maksimal: 268435456
maxEvenDividing rezultati: 268435446 kohëzgjatja 111.0064ms
maxEvenDividing2 rezultati: 268435446 kohëzgjatja 79.0045ms
maxEvenConjunction rezultati: 268435446 kohëzgjatja 114.0065ms
maxEvenConjunction2 rezultati: 268435446 kohëzgjatja 79.0045ms

pragu maksimal: 536870912
maxEvenDividing rezultati: 536870910 kohëzgjatja 107.0062ms
maxEvenDividing2 rezultati: 536870910 kohëzgjatja 76.0043ms
maxEvenConjunction rezultat: 536870910 kohëzgjatja 109.0062ms
maxEvenConjunction2 rezultat: 536870910 kohëzgjatja 80.0046ms

Nuk kam gjetur një shpjegim të qartë pse kompajleri Go nuk e optimizon kodin dhe gjithmonë kontrollon kushtin e dytë, edhe kur i pari është i gabuar — ndoshta ndaj kam humbur ndonjë detaj dhe nuk shoh një gabim të dukshëm? Apo duhet t'i jap disa udhëzime të veçanta kompajlerit? Do të isha i lumtur për komentet e ndihmës.

PS: Po, për të kaluar kohën, kam testuar teste të ngjashme në Java 5 dhe Java 7/8 — çdo gjë është e qartë, koha e ekzekutimit është e njëjtë.

Burimi: habr.com

Blini hosting të besueshëm për faqe interneti me mbrojtje nga DDoS, serverë VPS VDS 🔥 Blini hosting të besueshëm për faqe interneti me mbrojtje nga DDoS, serverë VPS VDS | ProHoster