Betingsten yn Go en harren eigenaardichheden

Tinke jo dat dizze twa opsjes foar testbetingsten binnen in lus lykweardich binne yn prestaasjes?

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


It begon allegear mei in "brain warming-up"; ik moast in foarbyld jaan fan in optimale syktocht nei it grutste even nûmer yn in array fan heule getallen [-x....x]. Ik frege my ôf hoefolle bettere prestaasjes soe wêze as ik logyske fermannichfâldigje mei 1 brûkte om út te finen oft in getal even is of net.


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

Myn programmearûnderfining yn Go is net heul wiidweidich, krekt mear as in jier en in heal, ik brûkte it, hoewol faaks, mar suver foar utilitaristyske doelen (goed, miskien útsein foar ien projekt relatearre oan in http-tsjinst mei hege lading), dus ik der mei begûn. Iepenje GoLand en skriuw in ienfâldige 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
}

Wy krije in resultaat dat lit sjen dat hoe heger de drompel, hoe faker fluktuaasjes yn prestaasjes ferskine.

Ferlykjemax 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

It is dúdlik dat yn dit gefal, foar ferskate drompels wy hawwe ferskillende sets fan test gegevens, de prosessor load (op myn i5-2540M laptop) fariearret om 20..30%, it ûnthâld beset troch de applikaasje rint fan GoLand is gemiddeld oer 813MB - dit hat ek ynfloed op de betrouberens fan it resultaat, jo moatte testgefallen op skiif bewarje en alle testen foar elke drompel isolearre fan elkoar útfiere.

En no, tinkend oer hoe't jo dit alles mei minimale kosten kinne útfiere, korrigearje ik de betingstkontrôle automatysk

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

op

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

Ik rin de tests wer ... en ik stopje neat te begripen :)

De tiid bestege oan útfiering begjint net mear te ferskillen troch persintaazjes/fraksjes fan in persint, mar troch 10..15%.Ik foegje gau noch 2 tests ta:

		
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
}

Ik rin it en krij dizze foto:initial array kapasiteit: 100000000

maksimum drompel: 128
maxEvenDividing resultaat: 126 doer 116.0066ms
maxEvenDividing2 resultaat: 126 doer 79.0045ms
maxEvenConjunction resultaat: 126 doer 114.0065ms
maxEvenConjunction2 resultaat: 126 doer 83.0048ms

maksimum drompel: 256
maxEvenDividing resultaat: 254 doer 111.0063ms
maxEvenDividing2 resultaat: 254 doer 77.0044ms
maxEvenConjunction resultaat: 254 doer 110.0063ms
maxEvenConjunction2 resultaat: 254 doer 80.0046ms

maksimum drompel: 512
maxEvenDividing resultaat: 510 doer 114.0066ms
maxEvenDividing2 resultaat: 510 doer 80.0045ms
maxEvenConjunction resultaat: 510 doer 110.0063ms
maxEvenConjunction2 resultaat: 510 doer 80.0046ms

maksimum drompel: 1024
maxEvenDividing resultaat: 1022 doer 109.0063ms
maxEvenDividing2 resultaat: 1022 doer 77.0044ms
maxEvenConjunction resultaat: 1022 doer 111.0063ms
maxEvenConjunction2 resultaat: 1022 doer 81.0047ms

maksimum drompel: 2048
maxEvenDividing resultaat: 2046 doer 114.0065ms
maxEvenDividing2 resultaat: 2046 doer 79.0045ms
maxEvenConjunction resultaat: 2046 doer 113.0065ms
maxEvenConjunction2 resultaat: 2046 doer 81.0046ms

maksimum drompel: 4096
maxEvenDividing resultaat: 4094 doer 114.0065ms
maxEvenDividing2 resultaat: 4094 doer 80.0046ms
maxEvenConjunction resultaat: 4094 doer 111.0063ms
maxEvenConjunction2 resultaat: 4094 doer 78.0045ms

maksimum drompel: 8192
maxEvenDividing resultaat: 8190 doer 107.0062ms
maxEvenDividing2 resultaat: 8190 doer 77.0044ms
maxEvenConjunction resultaat: 8190 doer 111.0063ms
maxEvenConjunction2 resultaat: 8190 doer 77.0044ms

maksimum drompel: 16384
maxEvenDividing resultaat: 16382 doer 109.0063ms
maxEvenDividing2 resultaat: 16382 doer 77.0044ms
maxEvenConjunction resultaat: 16382 doer 108.0062ms
maxEvenConjunction2 resultaat: 16382 doer 77.0044ms

maksimum drompel: 32768
maxEvenDividing resultaat: 32766 doer 112.0064ms
maxEvenDividing2 resultaat: 32766 doer 77.0044ms
maxEvenConjunction resultaat: 32766 doer 109.0062ms
maxEvenConjunction2 resultaat: 32766 doer 78.0045ms

maksimum drompel: 65536
maxEvenDividing resultaat: 65534 doer 109.0062ms
maxEvenDividing2 resultaat: 65534 doer 75.0043ms
maxEvenConjunction resultaat: 65534 doer 109.0063ms
maxEvenConjunction2 resultaat: 65534 doer 79.0045ms

maksimum drompel: 131072
maxEvenDividing resultaat: 131070 doer 108.0061ms
maxEvenDividing2 resultaat: 131070 doer 76.0044ms
maxEvenConjunction resultaat: 131070 doer 110.0063ms
maxEvenConjunction2 resultaat: 131070 doer 80.0046ms

maksimum drompel: 262144
maxEvenDividing resultaat: 262142 doer 110.0063ms
maxEvenDividing2 resultaat: 262142 doer 76.0044ms
maxEvenConjunction resultaat: 262142 doer 107.0061ms
maxEvenConjunction2 resultaat: 262142 doer 78.0044ms

maksimum drompel: 524288
maxEvenDividing resultaat: 524286 doer 109.0062ms
maxEvenDividing2 resultaat: 524286 doer 78.0045ms
maxEvenConjunction resultaat: 524286 doer 109.0062ms
maxEvenConjunction2 resultaat: 524286 doer 80.0046ms

maksimum drompel: 1048576
maxEvenDividing resultaat: 1048574 doer 109.0063ms
maxEvenDividing2 resultaat: 1048574 doer 80.0045ms
maxEvenConjunction resultaat: 1048574 doer 114.0066ms
maxEvenConjunction2 resultaat: 1048574 doer 78.0044ms

maksimum drompel: 2097152
maxEvenDividing resultaat: 2097150 doer 111.0064ms
maxEvenDividing2 resultaat: 2097150 doer 79.0045ms
maxEvenConjunction resultaat: 2097150 doer 112.0064ms
maxEvenConjunction2 resultaat: 2097150 doer 77.0044ms

maksimum drompel: 4194304
maxEvenDividing resultaat: 4194302 doer 111.0063ms
maxEvenDividing2 resultaat: 4194302 doer 78.0045ms
maxEvenConjunction resultaat: 4194302 doer 111.0063ms
maxEvenConjunction2 resultaat: 4194302 doer 77.0044ms

maksimum drompel: 8388608
maxEvenDividing resultaat: 8388606 doer 109.0062ms
maxEvenDividing2 resultaat: 8388606 doer 78.0045ms
maxEvenConjunction resultaat: 8388606 doer 114.0065ms
maxEvenConjunction2 resultaat: 8388606 doer 78.0045ms

maksimum drompel: 16777216
maxEvenDividing resultaat: 16777214 doer 109.0062ms
maxEvenDividing2 resultaat: 16777214 doer 77.0044ms
maxEvenConjunction resultaat: 16777214 doer 109.0063ms
maxEvenConjunction2 resultaat: 16777214 doer 77.0044ms

maksimum drompel: 33554432
maxEvenDividing resultaat: 33554430 doer 113.0065ms
maxEvenDividing2 resultaat: 33554430 doer 78.0045ms
maxEvenConjunction resultaat: 33554430 doer 110.0063ms
maxEvenConjunction2 resultaat: 33554430 doer 80.0045ms

maksimum drompel: 67108864
maxEvenDividing resultaat: 67108860 doer 112.0064ms
maxEvenDividing2 resultaat: 67108860 doer 77.0044ms
maxEvenConjunction resultaat: 67108860 doer 112.0064ms
maxEvenConjunction2 resultaat: 67108860 doer 80.0046ms

maksimum drompel: 134217728
maxEvenDividing resultaat: 134217726 doer 109.0063ms
maxEvenDividing2 resultaat: 134217726 doer 78.0044ms
maxEvenConjunction resultaat: 134217726 doer 114.0065ms
maxEvenConjunction2 resultaat: 134217726 doer 81.0047ms

maksimum drompel: 268435456
maxEvenDividing resultaat: 268435446 doer 111.0064ms
maxEvenDividing2 resultaat: 268435446 doer 79.0045ms
maxEvenConjunction resultaat: 268435446 doer 114.0065ms
maxEvenConjunction2 resultaat: 268435446 doer 79.0045ms

maksimum drompel: 536870912
maxEvenDividing resultaat: 536870910 doer 107.0062ms
maxEvenDividing2 resultaat: 536870910 doer 76.0043ms
maxEvenConjunction resultaat: 536870910 doer 109.0062ms
maxEvenConjunction2 resultaat: 536870910 doer 80.0046ms

Ik koe gjin dúdlike ferklearring fine wêrom't de Go-kompiler de koade net optimalisearret en altyd de twadde betingst kontrolearret, sels as de earste falsk is. Of miskien binne myn eagen gewoan wazig en sjoch ik gjin dúdlike flater? Of moatte jo wat spesjale ynstruksjes leverje oan 'e kompilator? Ik soe bliid wêze foar ferstannige opmerkingen.

PS: Ja, gewoan foar de wille rûn ik ferlykbere tests op Java 5 en Java 7/8 - alles is dúdlik, de útfieringstiid is itselde.

Boarne: www.habr.com

Add a comment