Konditiounen an Go an hir Quirks

Denkt Dir datt dës zwou Optiounen fir Testbedéngungen an enger Loop gläichwäerteg sinn an der Leeschtung?

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


Et huet alles ugefaang mat enger "Gehirerwärmung"; Ech hunn e Beispill vun enger optimaler Sich no der gréisster souguer Zuel an enger ganzer Zuel [-x....x] ze ginn. Ech hu mech gefrot wéi vill besser Leeschtung wier wann ech logesch Multiplikatioun mat 1 benotzt fir erauszefannen ob eng Zuel souguer ass oder net.


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

Meng Programméierungserfarung am Go ass net ganz extensiv, just iwwer annerhallwem Joer, ech hunn et benotzt, obwuel dacks, awer reng fir utilitaristesch Zwecker (gutt, vläicht ausser fir ee Projet am Zesummenhang mat engem High-load http Service), also ech ugefaang domat. Open GoLand a schreift en einfachen 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
        // Будем варьировать диапазон чисел от минимального 
        // до максимального. Чем меньше диапазон, тем больше 
        // процессорного времени будет уходить на операцию 
        // сравнения текущего числа, с ранее найденным и наоборот
	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
}

Mir kréien e Resultat dat weist datt wat méi héich de Schwell ass, wat méi dacks Schwankungen an der Leeschtung erschéngen.

Vergläichenmax 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

Et ass kloer datt an dësem Fall, fir verschidde Schwellen, verschidde Sätz vun Testdaten hunn, d'Prozessorbelaaschtung (op mengem i5-2540M Laptop) variéiert ongeféier 20..30%, d'Erënnerung besat vun der Applikatioun déi vu GoLand leeft ass am Duerchschnëtt ongeféier 813MB - dëst beaflosst och d'Zouverlässegkeet vum Resultat, Dir musst Testfäll op der Disk späicheren an all Tester fir all Schwell isoléiert vuneneen ausféieren.

An elo, iwwerdenken wéi ech dat alles mat minimale Käschten ëmsetzen, korrigéiere ech automatesch d'Konditiounscheck

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

op

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

Ech laafen d'Tester nach eng Kéier ... an ech verstinn net alles :)

D'Zäit, déi un der Ausféierung verbraucht gëtt, fänkt un net méi duerch Prozentzuelen / Fraktiounen vun engem Prozent ze ënnerscheeden, mee ëm 10..15%, Ech fügen séier nach 2 Tester derbäi:

		
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
}

Ech lafen et a kréien dëst Bild:initial Array Kapazitéit: 100000000

maximal Schwell: 128
maxEvenDividing Resultat: 126 Dauer 116.0066ms
maxEvenDividing2 Resultat: 126 Dauer 79.0045ms
maxEvenConjunction Resultat: 126 Dauer 114.0065ms
maxEvenConjunction2 Resultat: 126 Dauer 83.0048ms

maximal Schwell: 256
maxEvenDividing Resultat: 254 Dauer 111.0063ms
maxEvenDividing2 Resultat: 254 Dauer 77.0044ms
maxEvenConjunction Resultat: 254 Dauer 110.0063ms
maxEvenConjunction2 Resultat: 254 Dauer 80.0046ms

maximal Schwell: 512
maxEvenDividing Resultat: 510 Dauer 114.0066ms
maxEvenDividing2 Resultat: 510 Dauer 80.0045ms
maxEvenConjunction Resultat: 510 Dauer 110.0063ms
maxEvenConjunction2 Resultat: 510 Dauer 80.0046ms

maximal Schwell: 1024
maxEvenDividing Resultat: 1022 Dauer 109.0063ms
maxEvenDividing2 Resultat: 1022 Dauer 77.0044ms
maxEvenConjunction Resultat: 1022 Dauer 111.0063ms
maxEvenConjunction2 Resultat: 1022 Dauer 81.0047ms

maximal Schwell: 2048
maxEvenDividing Resultat: 2046 Dauer 114.0065ms
maxEvenDividing2 Resultat: 2046 Dauer 79.0045ms
maxEvenConjunction Resultat: 2046 Dauer 113.0065ms
maxEvenConjunction2 Resultat: 2046 Dauer 81.0046ms

maximal Schwell: 4096
maxEvenDividing Resultat: 4094 Dauer 114.0065ms
maxEvenDividing2 Resultat: 4094 Dauer 80.0046ms
maxEvenConjunction Resultat: 4094 Dauer 111.0063ms
maxEvenConjunction2 Resultat: 4094 Dauer 78.0045ms

maximal Schwell: 8192
maxEvenDividing Resultat: 8190 Dauer 107.0062ms
maxEvenDividing2 Resultat: 8190 Dauer 77.0044ms
maxEvenConjunction Resultat: 8190 Dauer 111.0063ms
maxEvenConjunction2 Resultat: 8190 Dauer 77.0044ms

maximal Schwell: 16384
maxEvenDividing Resultat: 16382 Dauer 109.0063ms
maxEvenDividing2 Resultat: 16382 Dauer 77.0044ms
maxEvenConjunction Resultat: 16382 Dauer 108.0062ms
maxEvenConjunction2 Resultat: 16382 Dauer 77.0044ms

maximal Schwell: 32768
maxEvenDividing Resultat: 32766 Dauer 112.0064ms
maxEvenDividing2 Resultat: 32766 Dauer 77.0044ms
maxEvenConjunction Resultat: 32766 Dauer 109.0062ms
maxEvenConjunction2 Resultat: 32766 Dauer 78.0045ms

maximal Schwell: 65536
maxEvenDividing Resultat: 65534 Dauer 109.0062ms
maxEvenDividing2 Resultat: 65534 Dauer 75.0043ms
maxEvenConjunction Resultat: 65534 Dauer 109.0063ms
maxEvenConjunction2 Resultat: 65534 Dauer 79.0045ms

maximal Schwell: 131072
maxEvenDividing Resultat: 131070 Dauer 108.0061ms
maxEvenDividing2 Resultat: 131070 Dauer 76.0044ms
maxEvenConjunction Resultat: 131070 Dauer 110.0063ms
maxEvenConjunction2 Resultat: 131070 Dauer 80.0046ms

maximal Schwell: 262144
maxEvenDividing Resultat: 262142 Dauer 110.0063ms
maxEvenDividing2 Resultat: 262142 Dauer 76.0044ms
maxEvenConjunction Resultat: 262142 Dauer 107.0061ms
maxEvenConjunction2 Resultat: 262142 Dauer 78.0044ms

maximal Schwell: 524288
maxEvenDividing Resultat: 524286 Dauer 109.0062ms
maxEvenDividing2 Resultat: 524286 Dauer 78.0045ms
maxEvenConjunction Resultat: 524286 Dauer 109.0062ms
maxEvenConjunction2 Resultat: 524286 Dauer 80.0046ms

maximal Schwell: 1048576
maxEvenDividing Resultat: 1048574 Dauer 109.0063ms
maxEvenDividing2 Resultat: 1048574 Dauer 80.0045ms
maxEvenConjunction Resultat: 1048574 Dauer 114.0066ms
maxEvenConjunction2 Resultat: 1048574 Dauer 78.0044ms

maximal Schwell: 2097152
maxEvenDividing Resultat: 2097150 Dauer 111.0064ms
maxEvenDividing2 Resultat: 2097150 Dauer 79.0045ms
maxEvenConjunction Resultat: 2097150 Dauer 112.0064ms
maxEvenConjunction2 Resultat: 2097150 Dauer 77.0044ms

maximal Schwell: 4194304
maxEvenDividing Resultat: 4194302 Dauer 111.0063ms
maxEvenDividing2 Resultat: 4194302 Dauer 78.0045ms
maxEvenConjunction Resultat: 4194302 Dauer 111.0063ms
maxEvenConjunction2 Resultat: 4194302 Dauer 77.0044ms

maximal Schwell: 8388608
maxEvenDividing Resultat: 8388606 Dauer 109.0062ms
maxEvenDividing2 Resultat: 8388606 Dauer 78.0045ms
maxEvenConjunction Resultat: 8388606 Dauer 114.0065ms
maxEvenConjunction2 Resultat: 8388606 Dauer 78.0045ms

maximal Schwell: 16777216
maxEvenDividing Resultat: 16777214 Dauer 109.0062ms
maxEvenDividing2 Resultat: 16777214 Dauer 77.0044ms
maxEvenConjunction Resultat: 16777214 Dauer 109.0063ms
maxEvenConjunction2 Resultat: 16777214 Dauer 77.0044ms

maximal Schwell: 33554432
maxEvenDividing Resultat: 33554430 Dauer 113.0065ms
maxEvenDividing2 Resultat: 33554430 Dauer 78.0045ms
maxEvenConjunction Resultat: 33554430 Dauer 110.0063ms
maxEvenConjunction2 Resultat: 33554430 Dauer 80.0045ms

maximal Schwell: 67108864
maxEvenDividing Resultat: 67108860 Dauer 112.0064ms
maxEvenDividing2 Resultat: 67108860 Dauer 77.0044ms
maxEvenConjunction Resultat: 67108860 Dauer 112.0064ms
maxEvenConjunction2 Resultat: 67108860 Dauer 80.0046ms

maximal Schwell: 134217728
maxEvenDividing Resultat: 134217726 Dauer 109.0063ms
maxEvenDividing2 Resultat: 134217726 Dauer 78.0044ms
maxEvenConjunction Resultat: 134217726 Dauer 114.0065ms
maxEvenConjunction2 Resultat: 134217726 Dauer 81.0047ms

maximal Schwell: 268435456
maxEvenDividing Resultat: 268435446 Dauer 111.0064ms
maxEvenDividing2 Resultat: 268435446 Dauer 79.0045ms
maxEvenConjunction Resultat: 268435446 Dauer 114.0065ms
maxEvenConjunction2 Resultat: 268435446 Dauer 79.0045ms

maximal Schwell: 536870912
maxEvenDividing Resultat: 536870910 Dauer 107.0062ms
maxEvenDividing2 Resultat: 536870910 Dauer 76.0043ms
maxEvenConjunction Resultat: 536870910 Dauer 109.0062ms
maxEvenConjunction2 Resultat: 536870910 Dauer 80.0046ms

Ech konnt keng kloer Erklärung fannen firwat de Go Compiler de Code net optiméiert an ëmmer déi zweet Konditioun kontrolléiert, och wann déi éischt falsch ass. Oder vläicht sinn meng Ae just blurry an ech gesinn keen offensichtleche Feeler? Oder musst Dir e puer speziell Instruktioune fir de Compiler ubidden? Ech wier frou fir verstänneg Kommentaren.

PS: Jo, just fir Spaass hunn ech ähnlech Tester op Java 5 an Java 7/8 gemaach - alles ass kloer, d'Ausféierungszäit ass d'selwecht.

Source: will.com

Setzt e Commentaire