Cundizioni in Go è e so peculiarità

Pensate chì queste duie opzioni per pruvà e cundizioni in un ciclu sò equivalenti in rendiment?

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


Tuttu hà cuminciatu cù un "riscaldamentu di u cervellu"; Aviu avutu da dà un esempiu di una ricerca ottima per u più grande numeru pari in una serie di interi [-x....x]. Mi dumandava quantu megliu rendimentu seria se aghju utilizatu a multiplicazione logica per 1 per sapè se un numeru hè ancu o micca.


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

A mo sperienza di prugrammazione in Go ùn hè micca assai estensiva, pocu più di un annu è mezu, l'aghju utilizatu, ancu s'ellu spessu, ma puramente per scopi utilitarii (bene, forse eccettu per un prughjettu ligatu à un serviziu http d'alta carica), cusì aghju. principiatu cun ellu. Aprite GoLand è scrivite una prova simplice


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
}

Avemu un risultatu chì mostra chì più altu hè u sogliu, più spessu appariscenu i fluttuazioni in u rendiment.

Compararemax 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

Hè chjaru chì in questu casu, per diverse soglie avemu parechji setti di dati di prova, a carica di u processatore (nantu à u mo laptop i5-2540M) varieghja intornu à 20..30%, a memoria occupata da l'applicazione chì corre da GoLand hè in media. circa 813MB - questu hè ancu affettatu l'affidabilità di u risultatu, avete bisognu di salvà i casi di teste nantu à u discu è eseguite tutte e teste per ogni soglia isolata l'una di l'altru.

È avà, pensendu à cumu implementà tuttu questu cù costi minimi, aghju automaticamente corregge a verificazione di cundizione

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

nantu

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

Eseguiu i testi di novu... è ùn smettu di capisce nunda :)

U tempu spentu nantu à l'esekzione principia à differisce micca più per percentuali / frazzioni di un percentu, ma da 10..15%. Aghju aghjustatu rapidamente 2 teste più:

		
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
}

L'aghju scappatu è uttene sta foto:capacità iniziale di l'array: 100000000

limite massima: 128
maxEvenDividing risultatu: 126 durata 116.0066ms
Risultato maxEvenDividing2: 126 durata 79.0045 ms
maxEvenConjunction risultatu: 126 durata 114.0065ms
maxEvenConjunction2 risultatu: 126 durata 83.0048ms

limite massima: 256
maxEvenDividing risultatu: 254 durata 111.0063ms
Risultato maxEvenDividing2: 254 durata 77.0044 ms
maxEvenConjunction risultatu: 254 durata 110.0063ms
maxEvenConjunction2 risultatu: 254 durata 80.0046ms

limite massima: 512
maxEvenDividing risultatu: 510 durata 114.0066ms
Risultato maxEvenDividing2: 510 durata 80.0045 ms
maxEvenConjunction risultatu: 510 durata 110.0063ms
maxEvenConjunction2 risultatu: 510 durata 80.0046ms

limite massima: 1024
maxEvenDividing risultatu: 1022 durata 109.0063ms
Risultato maxEvenDividing2: 1022 durata 77.0044 ms
maxEvenConjunction risultatu: 1022 durata 111.0063ms
maxEvenConjunction2 risultatu: 1022 durata 81.0047ms

limite massima: 2048
maxEvenDividing risultatu: 2046 durata 114.0065ms
Risultato maxEvenDividing2: 2046 durata 79.0045 ms
maxEvenConjunction risultatu: 2046 durata 113.0065ms
maxEvenConjunction2 risultatu: 2046 durata 81.0046ms

limite massima: 4096
maxEvenDividing risultatu: 4094 durata 114.0065ms
Risultato maxEvenDividing2: 4094 durata 80.0046 ms
maxEvenConjunction risultatu: 4094 durata 111.0063ms
maxEvenConjunction2 risultatu: 4094 durata 78.0045ms

limite massima: 8192
maxEvenDividing risultatu: 8190 durata 107.0062ms
Risultato maxEvenDividing2: 8190 durata 77.0044 ms
maxEvenConjunction risultatu: 8190 durata 111.0063ms
maxEvenConjunction2 risultatu: 8190 durata 77.0044ms

limite massima: 16384
maxEvenDividing risultatu: 16382 durata 109.0063ms
Risultato maxEvenDividing2: 16382 durata 77.0044 ms
maxEvenConjunction risultatu: 16382 durata 108.0062ms
maxEvenConjunction2 risultatu: 16382 durata 77.0044ms

limite massima: 32768
maxEvenDividing risultatu: 32766 durata 112.0064ms
Risultato maxEvenDividing2: 32766 durata 77.0044 ms
maxEvenConjunction risultatu: 32766 durata 109.0062ms
maxEvenConjunction2 risultatu: 32766 durata 78.0045ms

limite massima: 65536
maxEvenDividing risultatu: 65534 durata 109.0062ms
Risultato maxEvenDividing2: 65534 durata 75.0043 ms
maxEvenConjunction risultatu: 65534 durata 109.0063ms
maxEvenConjunction2 risultatu: 65534 durata 79.0045ms

limite massima: 131072
maxEvenDividing risultatu: 131070 durata 108.0061ms
Risultato maxEvenDividing2: 131070 durata 76.0044 ms
maxEvenConjunction risultatu: 131070 durata 110.0063ms
maxEvenConjunction2 risultatu: 131070 durata 80.0046ms

limite massima: 262144
maxEvenDividing risultatu: 262142 durata 110.0063ms
Risultato maxEvenDividing2: 262142 durata 76.0044 ms
maxEvenConjunction risultatu: 262142 durata 107.0061ms
maxEvenConjunction2 risultatu: 262142 durata 78.0044ms

limite massima: 524288
maxEvenDividing risultatu: 524286 durata 109.0062ms
Risultato maxEvenDividing2: 524286 durata 78.0045 ms
maxEvenConjunction risultatu: 524286 durata 109.0062ms
maxEvenConjunction2 risultatu: 524286 durata 80.0046ms

limite massima: 1048576
maxEvenDividing risultatu: 1048574 durata 109.0063ms
Risultato maxEvenDividing2: 1048574 durata 80.0045 ms
maxEvenConjunction risultatu: 1048574 durata 114.0066ms
maxEvenConjunction2 risultatu: 1048574 durata 78.0044ms

limite massima: 2097152
maxEvenDividing risultatu: 2097150 durata 111.0064ms
Risultato maxEvenDividing2: 2097150 durata 79.0045 ms
maxEvenConjunction risultatu: 2097150 durata 112.0064ms
maxEvenConjunction2 risultatu: 2097150 durata 77.0044ms

limite massima: 4194304
maxEvenDividing risultatu: 4194302 durata 111.0063ms
Risultato maxEvenDividing2: 4194302 durata 78.0045 ms
maxEvenConjunction risultatu: 4194302 durata 111.0063ms
maxEvenConjunction2 risultatu: 4194302 durata 77.0044ms

limite massima: 8388608
maxEvenDividing risultatu: 8388606 durata 109.0062ms
Risultato maxEvenDividing2: 8388606 durata 78.0045 ms
maxEvenConjunction risultatu: 8388606 durata 114.0065ms
maxEvenConjunction2 risultatu: 8388606 durata 78.0045ms

limite massima: 16777216
maxEvenDividing risultatu: 16777214 durata 109.0062ms
Risultato maxEvenDividing2: 16777214 durata 77.0044 ms
maxEvenConjunction risultatu: 16777214 durata 109.0063ms
maxEvenConjunction2 risultatu: 16777214 durata 77.0044ms

limite massima: 33554432
maxEvenDividing risultatu: 33554430 durata 113.0065ms
Risultato maxEvenDividing2: 33554430 durata 78.0045 ms
maxEvenConjunction risultatu: 33554430 durata 110.0063ms
maxEvenConjunction2 risultatu: 33554430 durata 80.0045ms

limite massima: 67108864
maxEvenDividing risultatu: 67108860 durata 112.0064ms
Risultato maxEvenDividing2: 67108860 durata 77.0044 ms
maxEvenConjunction risultatu: 67108860 durata 112.0064ms
maxEvenConjunction2 risultatu: 67108860 durata 80.0046ms

limite massima: 134217728
maxEvenDividing risultatu: 134217726 durata 109.0063ms
Risultato maxEvenDividing2: 134217726 durata 78.0044 ms
maxEvenConjunction risultatu: 134217726 durata 114.0065ms
maxEvenConjunction2 risultatu: 134217726 durata 81.0047ms

limite massima: 268435456
maxEvenDividing risultatu: 268435446 durata 111.0064ms
Risultato maxEvenDividing2: 268435446 durata 79.0045 ms
maxEvenConjunction risultatu: 268435446 durata 114.0065ms
maxEvenConjunction2 risultatu: 268435446 durata 79.0045ms

limite massima: 536870912
maxEvenDividing risultatu: 536870910 durata 107.0062ms
Risultato maxEvenDividing2: 536870910 durata 76.0043 ms
maxEvenConjunction risultatu: 536870910 durata 109.0062ms
maxEvenConjunction2 risultatu: 536870910 durata 80.0046ms

Ùn pudia truvà una spiegazione chjara perchè u compilatore Go ùn ottimisimu micca u codice è verifica sempre a seconda cundizione, ancu s'ellu u primu hè falsu. O forse i mo ochji sò solu sfocati è ùn vecu micca un sbagliu evidenti? O avete bisognu di furnisce qualchi struzzioni speciali à u compilatore? Saria cuntentu per i cumenti sensati.

PS: Iè, solu per divertimentu, aghju realizatu teste simili nantu à Java 5 è Java 7/8 - tuttu hè chjaru, u tempu d'esekzione hè u listessu.

Source: www.habr.com

Add a comment