Keadaan dalam Go dan keanehannya

Adakah anda fikir kedua-dua pilihan untuk menguji keadaan di dalam gelung adalah setara dalam prestasi?

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


Semuanya bermula dengan "memanaskan otak"; Saya terpaksa memberikan contoh carian optimum untuk nombor genap terbesar dalam susunan integer [-x....x]. Saya tertanya-tanya sejauh mana prestasi yang lebih baik jika saya menggunakan pendaraban logik dengan 1 untuk mengetahui sama ada nombor itu genap atau tidak.


//Ρƒ Ρ‡Π΅Ρ‚Π½Ρ‹Ρ… чисСл послСдний Π±ΠΈΡ‚ всСгда Ρ€Π°Π²Π΅Π½ 0
value & 1 == 0
//vs классичСский ΠΌΠ΅Ρ‚ΠΎΠ΄
value % 2 == 0

Pengalaman pengaturcaraan saya dalam Go tidak begitu luas, hanya lebih setahun setengah, saya menggunakannya, walaupun kerap, tetapi semata-mata untuk tujuan utilitarian (baik, mungkin kecuali untuk satu projek yang berkaitan dengan perkhidmatan http beban tinggi), jadi saya bermula dengannya. Buka GoLand dan tulis ujian mudah


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
}

Kami mendapat keputusan yang menunjukkan bahawa semakin tinggi ambang, semakin kerap turun naik dalam prestasi muncul.

Bandingkanmax 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

Adalah jelas bahawa dalam kes ini, untuk ambang yang berbeza kami mempunyai set data ujian yang berbeza, beban pemproses (pada komputer riba i5-2540M saya) berbeza-beza sekitar 20..30%, memori yang diduduki oleh aplikasi yang dijalankan dari GoLand adalah secara purata kira-kira 813MB - ini juga menjejaskan kebolehpercayaan keputusan, anda perlu menyimpan kes ujian pada cakera dan menjalankan semua ujian untuk setiap ambang secara berasingan antara satu sama lain.

Dan sekarang, memikirkan bagaimana untuk melaksanakan semua ini dengan kos yang minimum, saya secara automatik membetulkan pemeriksaan keadaan

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

pada

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

Saya menjalankan ujian sekali lagi... dan saya berhenti memahami apa-apa :)

Masa yang dibelanjakan untuk pelaksanaan mula berbeza bukan mengikut peratusan/pecahan peratus, tetapi sebanyak 10..15%. Saya cepat menambah 2 lagi ujian:

		
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
}

Saya menjalankannya dan mendapatkan gambar ini:kapasiti tatasusunan awal: 100000000

ambang maksimum: 128
maxEvenDividing hasil: 126 tempoh 116.0066ms
hasil maxEvenDividing2: 126 tempoh 79.0045ms
hasil maxEvenConjunction: 126 tempoh 114.0065ms
hasil maxEvenConjunction2: 126 tempoh 83.0048ms

ambang maksimum: 256
maxEvenDividing hasil: 254 tempoh 111.0063ms
hasil maxEvenDividing2: 254 tempoh 77.0044ms
hasil maxEvenConjunction: 254 tempoh 110.0063ms
hasil maxEvenConjunction2: 254 tempoh 80.0046ms

ambang maksimum: 512
maxEvenDividing hasil: 510 tempoh 114.0066ms
hasil maxEvenDividing2: 510 tempoh 80.0045ms
hasil maxEvenConjunction: 510 tempoh 110.0063ms
hasil maxEvenConjunction2: 510 tempoh 80.0046ms

ambang maksimum: 1024
maxEvenDividing hasil: 1022 tempoh 109.0063ms
hasil maxEvenDividing2: 1022 tempoh 77.0044ms
hasil maxEvenConjunction: 1022 tempoh 111.0063ms
hasil maxEvenConjunction2: 1022 tempoh 81.0047ms

ambang maksimum: 2048
maxEvenDividing hasil: 2046 tempoh 114.0065ms
hasil maxEvenDividing2: 2046 tempoh 79.0045ms
hasil maxEvenConjunction: 2046 tempoh 113.0065ms
hasil maxEvenConjunction2: 2046 tempoh 81.0046ms

ambang maksimum: 4096
maxEvenDividing hasil: 4094 tempoh 114.0065ms
hasil maxEvenDividing2: 4094 tempoh 80.0046ms
hasil maxEvenConjunction: 4094 tempoh 111.0063ms
hasil maxEvenConjunction2: 4094 tempoh 78.0045ms

ambang maksimum: 8192
maxEvenDividing hasil: 8190 tempoh 107.0062ms
hasil maxEvenDividing2: 8190 tempoh 77.0044ms
hasil maxEvenConjunction: 8190 tempoh 111.0063ms
hasil maxEvenConjunction2: 8190 tempoh 77.0044ms

ambang maksimum: 16384
maxEvenDividing hasil: 16382 tempoh 109.0063ms
hasil maxEvenDividing2: 16382 tempoh 77.0044ms
hasil maxEvenConjunction: 16382 tempoh 108.0062ms
hasil maxEvenConjunction2: 16382 tempoh 77.0044ms

ambang maksimum: 32768
maxEvenDividing hasil: 32766 tempoh 112.0064ms
hasil maxEvenDividing2: 32766 tempoh 77.0044ms
hasil maxEvenConjunction: 32766 tempoh 109.0062ms
hasil maxEvenConjunction2: 32766 tempoh 78.0045ms

ambang maksimum: 65536
maxEvenDividing hasil: 65534 tempoh 109.0062ms
hasil maxEvenDividing2: 65534 tempoh 75.0043ms
hasil maxEvenConjunction: 65534 tempoh 109.0063ms
hasil maxEvenConjunction2: 65534 tempoh 79.0045ms

ambang maksimum: 131072
maxEvenDividing hasil: 131070 tempoh 108.0061ms
hasil maxEvenDividing2: 131070 tempoh 76.0044ms
hasil maxEvenConjunction: 131070 tempoh 110.0063ms
hasil maxEvenConjunction2: 131070 tempoh 80.0046ms

ambang maksimum: 262144
maxEvenDividing hasil: 262142 tempoh 110.0063ms
hasil maxEvenDividing2: 262142 tempoh 76.0044ms
hasil maxEvenConjunction: 262142 tempoh 107.0061ms
hasil maxEvenConjunction2: 262142 tempoh 78.0044ms

ambang maksimum: 524288
maxEvenDividing hasil: 524286 tempoh 109.0062ms
hasil maxEvenDividing2: 524286 tempoh 78.0045ms
hasil maxEvenConjunction: 524286 tempoh 109.0062ms
hasil maxEvenConjunction2: 524286 tempoh 80.0046ms

ambang maksimum: 1048576
maxEvenDividing hasil: 1048574 tempoh 109.0063ms
hasil maxEvenDividing2: 1048574 tempoh 80.0045ms
hasil maxEvenConjunction: 1048574 tempoh 114.0066ms
hasil maxEvenConjunction2: 1048574 tempoh 78.0044ms

ambang maksimum: 2097152
maxEvenDividing hasil: 2097150 tempoh 111.0064ms
hasil maxEvenDividing2: 2097150 tempoh 79.0045ms
hasil maxEvenConjunction: 2097150 tempoh 112.0064ms
hasil maxEvenConjunction2: 2097150 tempoh 77.0044ms

ambang maksimum: 4194304
maxEvenDividing hasil: 4194302 tempoh 111.0063ms
hasil maxEvenDividing2: 4194302 tempoh 78.0045ms
hasil maxEvenConjunction: 4194302 tempoh 111.0063ms
hasil maxEvenConjunction2: 4194302 tempoh 77.0044ms

ambang maksimum: 8388608
maxEvenDividing hasil: 8388606 tempoh 109.0062ms
hasil maxEvenDividing2: 8388606 tempoh 78.0045ms
hasil maxEvenConjunction: 8388606 tempoh 114.0065ms
hasil maxEvenConjunction2: 8388606 tempoh 78.0045ms

ambang maksimum: 16777216
maxEvenDividing hasil: 16777214 tempoh 109.0062ms
hasil maxEvenDividing2: 16777214 tempoh 77.0044ms
hasil maxEvenConjunction: 16777214 tempoh 109.0063ms
hasil maxEvenConjunction2: 16777214 tempoh 77.0044ms

ambang maksimum: 33554432
maxEvenDividing hasil: 33554430 tempoh 113.0065ms
hasil maxEvenDividing2: 33554430 tempoh 78.0045ms
hasil maxEvenConjunction: 33554430 tempoh 110.0063ms
hasil maxEvenConjunction2: 33554430 tempoh 80.0045ms

ambang maksimum: 67108864
maxEvenDividing hasil: 67108860 tempoh 112.0064ms
hasil maxEvenDividing2: 67108860 tempoh 77.0044ms
hasil maxEvenConjunction: 67108860 tempoh 112.0064ms
hasil maxEvenConjunction2: 67108860 tempoh 80.0046ms

ambang maksimum: 134217728
maxEvenDividing hasil: 134217726 tempoh 109.0063ms
hasil maxEvenDividing2: 134217726 tempoh 78.0044ms
hasil maxEvenConjunction: 134217726 tempoh 114.0065ms
hasil maxEvenConjunction2: 134217726 tempoh 81.0047ms

ambang maksimum: 268435456
maxEvenDividing hasil: 268435446 tempoh 111.0064ms
hasil maxEvenDividing2: 268435446 tempoh 79.0045ms
hasil maxEvenConjunction: 268435446 tempoh 114.0065ms
hasil maxEvenConjunction2: 268435446 tempoh 79.0045ms

ambang maksimum: 536870912
maxEvenDividing hasil: 536870910 tempoh 107.0062ms
hasil maxEvenDividing2: 536870910 tempoh 76.0043ms
hasil maxEvenConjunction: 536870910 tempoh 109.0062ms
hasil maxEvenConjunction2: 536870910 tempoh 80.0046ms

Saya tidak dapat mencari penjelasan yang jelas mengapa pengkompil Go tidak mengoptimumkan kod dan sentiasa menyemak syarat kedua, walaupun yang pertama adalah palsu. Atau mungkin mata saya hanya kabur dan saya tidak nampak sebarang kesilapan yang jelas? Atau adakah anda perlu memberikan beberapa arahan khas kepada pengkompil? Saya akan gembira untuk komen yang masuk akal.

PS: Ya, hanya untuk keseronokan, saya menjalankan ujian serupa pada Java 5 dan Java 7/8 - semuanya jelas, masa pelaksanaan adalah sama.

Sumber: www.habr.com

Tambah komen