Kondisi di Go dan keunikannya

Apakah menurut Anda kedua opsi untuk kondisi pengujian di dalam loop ini memiliki kinerja yang setara?

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


Semuanya dimulai dengan β€œpemanasan otak”; Saya harus memberikan contoh pencarian optimal untuk bilangan genap terbesar dalam array bilangan bulat [-x....x]. Saya bertanya-tanya seberapa baik kinerjanya jika saya menggunakan perkalian logika dengan 1 untuk mengetahui apakah suatu bilangan genap atau tidak.


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

Pengalaman pemrograman saya di Go tidak terlalu luas, hanya lebih dari satu setengah tahun, saya menggunakannya, meskipun sering, tetapi murni untuk tujuan utilitarian (yah, mungkin kecuali untuk satu proyek yang terkait dengan layanan http beban tinggi), jadi saya dimulai dengan itu. Buka GoLand dan tulis tes sederhana


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 mendapatkan hasil yang menunjukkan bahwa semakin tinggi ambang batas, semakin sering muncul fluktuasi kinerja.

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

Jelas bahwa dalam hal ini, untuk ambang batas yang berbeda kami memiliki kumpulan data pengujian yang berbeda, beban prosesor (pada laptop i5-2540M saya) bervariasi sekitar 20..30%, memori yang ditempati oleh aplikasi yang dijalankan dari GoLand rata-rata sekitar 813MB - ini juga mempengaruhi keandalan hasil, Anda perlu menyimpan kasus pengujian pada disk dan menjalankan semua pengujian untuk setiap ambang batas secara terpisah satu sama lain.

Dan sekarang, memikirkan bagaimana menerapkan semua ini dengan biaya minimal, saya secara otomatis memperbaiki pemeriksaan kondisi

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

pada

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

Saya menjalankan tes lagi... dan saya berhenti memahami apa pun :)

Waktu yang dihabiskan untuk eksekusi mulai berbeda tidak lagi berdasarkan persentase/pecahan persen, tetapi sebesar 10..15%.Saya segera menambahkan 2 tes lagi:

		
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:kapasitas array awal: 100000000

ambang batas maksimal: 128
hasil maxEvenDividing: 126 durasi 116.0066ms
hasil maxEvenDividing2: 126 durasi 79.0045ms
hasil maxEvenConjunction: 126 durasi 114.0065ms
hasil maxEvenConjunction2: 126 durasi 83.0048ms

ambang batas maksimal: 256
hasil maxEvenDividing: 254 durasi 111.0063ms
hasil maxEvenDividing2: 254 durasi 77.0044ms
hasil maxEvenConjunction: 254 durasi 110.0063ms
hasil maxEvenConjunction2: 254 durasi 80.0046ms

ambang batas maksimal: 512
hasil maxEvenDividing: 510 durasi 114.0066ms
hasil maxEvenDividing2: 510 durasi 80.0045ms
hasil maxEvenConjunction: 510 durasi 110.0063ms
hasil maxEvenConjunction2: 510 durasi 80.0046ms

ambang batas maksimal: 1024
hasil maxEvenDividing: 1022 durasi 109.0063ms
hasil maxEvenDividing2: 1022 durasi 77.0044ms
hasil maxEvenConjunction: 1022 durasi 111.0063ms
hasil maxEvenConjunction2: 1022 durasi 81.0047ms

ambang batas maksimal: 2048
hasil maxEvenDividing: 2046 durasi 114.0065ms
hasil maxEvenDividing2: 2046 durasi 79.0045ms
hasil maxEvenConjunction: 2046 durasi 113.0065ms
hasil maxEvenConjunction2: 2046 durasi 81.0046ms

ambang batas maksimal: 4096
hasil maxEvenDividing: 4094 durasi 114.0065ms
hasil maxEvenDividing2: 4094 durasi 80.0046ms
hasil maxEvenConjunction: 4094 durasi 111.0063ms
hasil maxEvenConjunction2: 4094 durasi 78.0045ms

ambang batas maksimal: 8192
hasil maxEvenDividing: 8190 durasi 107.0062ms
hasil maxEvenDividing2: 8190 durasi 77.0044ms
hasil maxEvenConjunction: 8190 durasi 111.0063ms
hasil maxEvenConjunction2: 8190 durasi 77.0044ms

ambang batas maksimal: 16384
hasil maxEvenDividing: 16382 durasi 109.0063ms
hasil maxEvenDividing2: 16382 durasi 77.0044ms
hasil maxEvenConjunction: 16382 durasi 108.0062ms
hasil maxEvenConjunction2: 16382 durasi 77.0044ms

ambang batas maksimal: 32768
hasil maxEvenDividing: 32766 durasi 112.0064ms
hasil maxEvenDividing2: 32766 durasi 77.0044ms
hasil maxEvenConjunction: 32766 durasi 109.0062ms
hasil maxEvenConjunction2: 32766 durasi 78.0045ms

ambang batas maksimal: 65536
hasil maxEvenDividing: 65534 durasi 109.0062ms
hasil maxEvenDividing2: 65534 durasi 75.0043ms
hasil maxEvenConjunction: 65534 durasi 109.0063ms
hasil maxEvenConjunction2: 65534 durasi 79.0045ms

ambang batas maksimal: 131072
hasil maxEvenDividing: 131070 durasi 108.0061ms
hasil maxEvenDividing2: 131070 durasi 76.0044ms
hasil maxEvenConjunction: 131070 durasi 110.0063ms
hasil maxEvenConjunction2: 131070 durasi 80.0046ms

ambang batas maksimal: 262144
hasil maxEvenDividing: 262142 durasi 110.0063ms
hasil maxEvenDividing2: 262142 durasi 76.0044ms
hasil maxEvenConjunction: 262142 durasi 107.0061ms
hasil maxEvenConjunction2: 262142 durasi 78.0044ms

ambang batas maksimal: 524288
hasil maxEvenDividing: 524286 durasi 109.0062ms
hasil maxEvenDividing2: 524286 durasi 78.0045ms
hasil maxEvenConjunction: 524286 durasi 109.0062ms
hasil maxEvenConjunction2: 524286 durasi 80.0046ms

ambang batas maksimal: 1048576
hasil maxEvenDividing: 1048574 durasi 109.0063ms
hasil maxEvenDividing2: 1048574 durasi 80.0045ms
hasil maxEvenConjunction: 1048574 durasi 114.0066ms
hasil maxEvenConjunction2: 1048574 durasi 78.0044ms

ambang batas maksimal: 2097152
hasil maxEvenDividing: 2097150 durasi 111.0064ms
hasil maxEvenDividing2: 2097150 durasi 79.0045ms
hasil maxEvenConjunction: 2097150 durasi 112.0064ms
hasil maxEvenConjunction2: 2097150 durasi 77.0044ms

ambang batas maksimal: 4194304
hasil maxEvenDividing: 4194302 durasi 111.0063ms
hasil maxEvenDividing2: 4194302 durasi 78.0045ms
hasil maxEvenConjunction: 4194302 durasi 111.0063ms
hasil maxEvenConjunction2: 4194302 durasi 77.0044ms

ambang batas maksimal: 8388608
hasil maxEvenDividing: 8388606 durasi 109.0062ms
hasil maxEvenDividing2: 8388606 durasi 78.0045ms
hasil maxEvenConjunction: 8388606 durasi 114.0065ms
hasil maxEvenConjunction2: 8388606 durasi 78.0045ms

ambang batas maksimal: 16777216
hasil maxEvenDividing: 16777214 durasi 109.0062ms
hasil maxEvenDividing2: 16777214 durasi 77.0044ms
hasil maxEvenConjunction: 16777214 durasi 109.0063ms
hasil maxEvenConjunction2: 16777214 durasi 77.0044ms

ambang batas maksimal: 33554432
hasil maxEvenDividing: 33554430 durasi 113.0065ms
hasil maxEvenDividing2: 33554430 durasi 78.0045ms
hasil maxEvenConjunction: 33554430 durasi 110.0063ms
hasil maxEvenConjunction2: 33554430 durasi 80.0045ms

ambang batas maksimal: 67108864
hasil maxEvenDividing: 67108860 durasi 112.0064ms
hasil maxEvenDividing2: 67108860 durasi 77.0044ms
hasil maxEvenConjunction: 67108860 durasi 112.0064ms
hasil maxEvenConjunction2: 67108860 durasi 80.0046ms

ambang batas maksimal: 134217728
hasil maxEvenDividing: 134217726 durasi 109.0063ms
hasil maxEvenDividing2: 134217726 durasi 78.0044ms
hasil maxEvenConjunction: 134217726 durasi 114.0065ms
hasil maxEvenConjunction2: 134217726 durasi 81.0047ms

ambang batas maksimal: 268435456
hasil maxEvenDividing: 268435446 durasi 111.0064ms
hasil maxEvenDividing2: 268435446 durasi 79.0045ms
hasil maxEvenConjunction: 268435446 durasi 114.0065ms
hasil maxEvenConjunction2: 268435446 durasi 79.0045ms

ambang batas maksimal: 536870912
hasil maxEvenDividing: 536870910 durasi 107.0062ms
hasil maxEvenDividing2: 536870910 durasi 76.0043ms
hasil maxEvenConjunction: 536870910 durasi 109.0062ms
hasil maxEvenConjunction2: 536870910 durasi 80.0046ms

Saya tidak dapat menemukan penjelasan yang jelas mengapa kompiler Go tidak mengoptimalkan kode dan selalu memeriksa kondisi kedua, meskipun kondisi pertama salah. Atau mungkin mataku hanya buram dan tidak melihat kesalahan yang jelas? Atau apakah Anda perlu memberikan beberapa instruksi khusus kepada kompiler? Saya akan senang untuk komentar yang masuk akal.

PS: Ya, hanya untuk bersenang-senang, saya menjalankan tes serupa di Java 5 dan Java 7/8 - semuanya jelas, waktu eksekusinya sama.

Sumber: www.habr.com

Tambah komentar