Die Eigenheiten von Go und deren Merkwürdigkeiten

Glauben Sie, dass diese beiden Varianten zur Bedingungsprüfung in einer Schleife hinsichtlich der Leistung äquivalent sind?

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


Alles begann mit einem „Gedankenwärmer“, ich sollte ein Beispiel für die optimale Suche nach der größten geraden Zahl in einem Array von ganzen Zahlen [-x….x] geben. Es interessierte mich, wie viel höher die Leistung wäre, wenn man zur Feststellung, ob eine Zahl gerade ist oder nicht, logische Multiplikation mit 1 verwendet.


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

Meine Programmiererfahrung mit Go ist nicht sehr groß, etwas mehr als anderthalb Jahre, obwohl ich es oft verwendet habe, jedoch hauptsächlich zu nützlichen Zwecken (außer vielleicht bei einem Projekt, das mit einem hochbelasteten HTTP-Dienst verbunden war), weshalb ich genau damit begann. Lassen Sie uns GoLand öffnen und einen einfachen Test schreiben.


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("anfängliche Array-Kapazität: " + fmt.Sprint(size))
	var maxValue int32
        // Wir variieren den Zahlenbereich
        // von minimal bis maximal. Je kleiner der Bereich, desto mehr
        // Prozessorzeit wird für den Vergleich der aktuellen Zahl
        // mit der zuvor gefundenen benötigt und umgekehrt
	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
}

Das Ergebnis zeigt, dass mit einem höheren Threshold die Schwankungen in der Performance häufiger auftreten.

Vergleichen SieMaximaler Schwellenwert: 128
maxEvenDividing Ergebnis: 126 Dauer 116,0067 ms
maxEvenConjunction Ergebnis: 126 Dauer 116,0066 ms

max Threshold: 16384
maxEvenDividing Ergebnis: 16382 Dauer 115.0066 ms
maxEvenConjunction Ergebnis: 16382 Dauer 111.0064 ms

......

max Threshold: 8388608
maxEvenDividing Ergebnis: 8388606 Dauer 109.0063 ms
maxEvenConjunction Ergebnis: 8388606 Dauer 109.0062 ms

max Threshold: 16777216
maxEvenDividing Ergebnis: 16777214 Dauer 108.0062 ms
maxEvenConjunction Ergebnis: 16777214 Dauer 109.0062 ms

max Threshold: 33554432
maxEvenDividing Ergebnis: 33554430 Dauer 114.0066 ms
maxEvenConjunction Ergebnis: 33554430 Dauer 110.0063 ms

max Threshold: 67108864
maxEvenDividing Ergebnis: 67108860 Dauer 111.0064 ms
maxEvenConjunction Ergebnis: 67108860 Dauer 109.0062 ms

max Threshold: 134217728
maxEvenDividing Ergebnis: 134217726 Dauer 108.0062 ms
maxEvenConjunction Ergebnis: 134217726 Dauer 109.0063 ms

max Threshold: 268435456
maxEvenDividing Ergebnis: 268435446 Dauer 111.0063 ms
maxEvenConjunction Ergebnis: 268435446 Dauer 110.0063 ms

Es ist klar, dass wir bei unterschiedlichen Thresholds verschiedene Testdatensätze haben. Die CPU-Auslastung (auf meinem Laptop i5-2540M) schwankt etwa zwischen 20 und 30 %, und der Speicher, den die Anwendung benötigt, die aus GoLand gestartet wurde, liegt im Durchschnitt bei ca. 813 MB. Das beeinflusst ebenfalls die Genauigkeit der Ergebnisse. Es sollte implementiert werden, dass Testsets auf der Festplatte gespeichert und alle Tests für jeden Threshold isoliert voneinander durchgeführt werden.

Während ich darüber nachdenke, wie ich das alles mit minimalen Kosten umsetzen kann, korrigiere ich automatisch die Bedingungsüberprüfung.

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

findet man

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

Ich starte die Tests erneut … und höre auf, irgendetwas zu verstehen 🙂

Die benötigte Zeit für die Ausführung beginnt sich nicht nur um Prozentsätze, sondern um 10..15% zu unterscheiden. Ich füge schnell noch 2 Tests hinzu:

		
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
}

Ich starte und erhalte folgendes Bild:initiale Array-Kapazität: 100000000

Maximaler Schwellenwert: 128
maxEvenDividing Ergebnis: 126 Dauer 116.0066ms
maxEvenDividing2 Ergebnis: 126 Dauer 79.0045ms
maxEvenConjunction Ergebnis: 126 Dauer 114.0065ms
maxEvenConjunction2 Ergebnis: 126 Dauer 83.0048ms

maximale Schwelle: 256
maxEvenDividing Ergebnis: 254 Dauer 111.0063ms
maxEvenDividing2 Ergebnis: 254 Dauer 77.0044ms
maxEvenConjunction Ergebnis: 254 Dauer 110.0063ms
maxEvenConjunction2 Ergebnis: 254 Dauer 80.0046ms

maximale Schwelle: 512
maxEvenDividing Ergebnis: 510 Dauer 114.0066ms
maxEvenDividing2 Ergebnis: 510 Dauer 80.0045ms
maxEvenConjunction Ergebnis: 510 Dauer 110.0063ms
maxEvenConjunction2 Ergebnis: 510 Dauer 80.0046ms

max Schwelle: 1024
maxEvenDividing Ergebnis: 1022 Dauer 109.0063ms
maxEvenDividing2 Ergebnis: 1022 Dauer 77.0044ms
maxEvenConjunction Ergebnis: 1022 Dauer 111.0063ms
maxEvenConjunction2 Ergebnis: 1022 Dauer 81.0047ms

max Schwelle: 2048
maxEvenDividing Ergebnis: 2046 Dauer 114.0065ms
maxEvenDividing2 Ergebnis: 2046 Dauer 79.0045ms
maxEvenConjunction Ergebnis: 2046 Dauer 113.0065ms
maxEvenConjunction2 Ergebnis: 2046 Dauer 81.0046ms

max Schwelle: 4096
maxEvenDividing Ergebnis: 4094 Dauer 114.0065ms
maxEvenDividing2 Ergebnis: 4094 Dauer 80.0046ms
maxEvenConjunction Ergebnis: 4094 Dauer 111.0063ms
maxEvenConjunction2 Ergebnis: 4094 Dauer 78.0045ms

max Schwelle: 8192
maxEvenDividing Ergebnis: 8190 Dauer 107.0062ms
maxEvenDividing2 Ergebnis: 8190 Dauer 77.0044ms
maxEvenConjunction Ergebnis: 8190 Dauer 111.0063ms
maxEvenConjunction2 Ergebnis: 8190 Dauer 77.0044ms

max Threshold: 16384
maxEvenDividing Ergebnis: 16382 Dauer 109.0063ms
maxEvenDividing2 Ergebnis: 16382 Dauer 77.0044ms
maxEvenConjunction Ergebnis: 16382 Dauer 108.0062ms
maxEvenConjunction2 Ergebnis: 16382 Dauer 77.0044ms

max Schwelle: 32768
maxEvenDividing Ergebnis: 32766 Dauer 112.0064ms
maxEvenDividing2 Ergebnis: 32766 Dauer 77.0044ms
maxEvenConjunction Ergebnis: 32766 Dauer 109.0062ms
maxEvenConjunction2 Ergebnis: 32766 Dauer 78.0045ms

max Schwelle: 65536
maxEvenDividing Ergebnis: 65534 Dauer 109.0062ms
maxEvenDividing2 Ergebnis: 65534 Dauer 75.0043ms
maxEvenConjunction Ergebnis: 65534 Dauer 109.0063ms
maxEvenConjunction2 Ergebnis: 65534 Dauer 79.0045ms

max Schwelle: 131072
maxEvenDividing Ergebnis: 131070 Dauer 108.0061ms
maxEvenDividing2 Ergebnis: 131070 Dauer 76.0044ms
maxEvenConjunction Ergebnis: 131070 Dauer 110.0063ms
maxEvenConjunction2 Ergebnis: 131070 Dauer 80.0046ms

max Schwelle: 262144
maxEvenDividing Ergebnis: 262142 Dauer 110,0063 ms
maxEvenDividing2 Ergebnis: 262142 Dauer 76,0044 ms
maxEvenConjunction Ergebnis: 262142 Dauer 107,0061 ms
maxEvenConjunction2 Ergebnis: 262142 Dauer 78,0044 ms

max Schwelle: 524288
maxEvenDividing Ergebnis: 524286 Dauer 109,0062 ms
maxEvenDividing2 Ergebnis: 524286 Dauer 78,0045 ms
maxEvenConjunction Ergebnis: 524286 Dauer 109,0062 ms
maxEvenConjunction2 Ergebnis: 524286 Dauer 80,0046 ms

max Schwelle: 1048576
maxEvenDividing Ergebnis: 1048574 Dauer 109,0063 ms
maxEvenDividing2 Ergebnis: 1048574 Dauer 80,0045 ms
maxEvenConjunction Ergebnis: 1048574 Dauer 114,0066 ms
maxEvenConjunction2 Ergebnis: 1048574 Dauer 78,0044 ms

max Schwelle: 2097152
maxEvenDividing Ergebnis: 2097150 Dauer 111,0064 ms
maxEvenDividing2 Ergebnis: 2097150 Dauer 79,0045 ms
maxEvenConjunction Ergebnis: 2097150 Dauer 112,0064 ms
maxEvenConjunction2 Ergebnis: 2097150 Dauer 77,0044 ms

max Schwelle: 4194304
maxEvenDividing Ergebnis: 4194302 Dauer 111,0063 ms
maxEvenDividing2 Ergebnis: 4194302 Dauer 78,0045 ms
maxEvenConjunction Ergebnis: 4194302 Dauer 111,0063 ms
maxEvenConjunction2 Ergebnis: 4194302 Dauer 77,0044 ms

max Threshold: 8388608
maxEvenDividing Ergebnis: 8388606 Dauer 109,0062 ms
maxEvenDividing2 Ergebnis: 8388606 Dauer 78,0045 ms
maxEvenConjunction Ergebnis: 8388606 Dauer 114,0065 ms
maxEvenConjunction2 Ergebnis: 8388606 Dauer 78,0045 ms

max Threshold: 16777216
maxEvenDividing Ergebnis: 16777214 Dauer 109,0062 ms
maxEvenDividing2 Ergebnis: 16777214 Dauer 77,0044 ms
maxEvenConjunction Ergebnis: 16777214 Dauer 109,0063 ms
maxEvenConjunction2 Ergebnis: 16777214 Dauer 77,0044 ms

max Threshold: 33554432
maxEvenDividing Ergebnis: 33554430 Dauer 113,0065 ms
maxEvenDividing2 Ergebnis: 33554430 Dauer 78,0045 ms
maxEvenConjunction Ergebnis: 33554430 Dauer 110.0063 ms
maxEvenConjunction2 Ergebnis: 33554430 Dauer 80,0045 ms

max Threshold: 67108864
maxEvenDividing Ergebnis: 67108860 Dauer 112,0064 ms
maxEvenDividing2 Ergebnis: 67108860 Dauer 77,0044 ms
maxEvenConjunction Ergebnis: 67108860 Dauer 112,0064 ms
maxEvenConjunction2 Ergebnis: 67108860 Dauer 80,0046 ms

max Threshold: 134217728
maxEvenDividing Ergebnis: 134217726 Dauer 109,0063 ms
maxEvenDividing2 Ergebnis: 134217726 Dauer 78,0044 ms
maxEvenConjunction Ergebnis: 134217726 Dauer 114,0065 ms
maxEvenConjunction2 Ergebnis: 134217726 Dauer 81,0047 ms

max Threshold: 268435456
maxEvenDividing Ergebnis: 268435446 Dauer 111,0064 ms
maxEvenDividing2 Ergebnis: 268435446 Dauer 79,0045 ms
maxEvenConjunction Ergebnis: 268435446 Dauer 114,0065 ms
maxEvenConjunction2 Ergebnis: 268435446 Dauer 79,0045 ms

maximale Schwelle: 536870912
maxEvenDividing Ergebnis: 536870910 Dauer 107,0062 ms
maxEvenDividing2 Ergebnis: 536870910 Dauer 76,0043 ms
maxEvenConjunction Ergebnis: 536870910 Dauer 109,0062 ms
maxEvenConjunction2 Ergebnis: 536870910 Dauer 80,0046 ms

Ich habe keine klare Erklärung gefunden, warum der Go- Compiler den Code nicht optimiert und immer die zweite Bedingung überprüft, auch wenn die erste falsch ist – vielleicht habe ich einfach nicht das Offensichtliche gesehen? Oder muss ich dem Compiler spezielle Anweisungen geben? Ich würde mich über hilfreiche Kommentare freuen.

PS: Ja, aus Interesse habe ich ähnliche Tests mit Java 5 und Java 7/8 durchgeführt – alles klar, die Ausführungszeit ist gleich.

Quelle: habr.com

Купить надежный хостинг для сайтов с защитой от DDoS, VPS VDS серверы 🔥 Купить надежный хостинг для сайтов с защитой от DDoS, VPS VDS серверы | ProHoster