Go-ի պայմանները և դրանց տարօրինակությունները

Ի՞նչ եք կարծում, հանգույցի ներսում փորձարկման պայմանների այս երկու տարբերակները համարժեք են կատարողականով:

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


Ամեն ինչ սկսվեց «ուղեղի տաքացումից», ես պետք է տայի [-x...x] ամբողջ թվերի զանգվածում ամենամեծ զույգ թվի օպտիմալ որոնման օրինակ: Ես մտածում էի, թե որքան ավելի լավ կատարողական կլիներ, եթե ես օգտագործեի տրամաբանական բազմապատկումը 1-ով` պարզելու համար, թե արդյոք թիվը զույգ է, թե ոչ:


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

Իմ ծրագրավորման փորձը Go-ում այնքան էլ ընդարձակ չէ, ընդամենը մեկուկես տարուց ավելի, ես այն օգտագործել եմ, թեև հաճախ, բայց զուտ օգտակար նպատակներով (լավ, միգուցե բացառությամբ բարձր բեռնված http ծառայության հետ կապված մեկ նախագծի), այնպես որ ես սկսվեց դրանով: Բացեք GoLand-ը և գրեք պարզ թեստ


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
}

Մենք ստանում ենք արդյունք, որը ցույց է տալիս, որ որքան բարձր է շեմը, այնքան հաճախ են առաջանում կատարողականի տատանումներ։

Համեմատեքmax 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

Հասկանալի է, որ այս դեպքում, տարբեր շեմերի համար մենք ունենք փորձարկման տվյալների տարբեր հավաքածուներ, պրոցեսորի ծանրաբեռնվածությունը (իմ i5-2540M նոութբուքի վրա) տատանվում է մոտ 20..30%, GoLand-ից աշխատող հավելվածի զբաղեցրած հիշողությունը միջինում է: մոտ 813 ՄԲ - սա նույնպես ազդում է արդյունքի հուսալիության վրա, դուք պետք է պահպանեք թեստային դեպքերը սկավառակի վրա և կատարեք բոլոր թեստերը յուրաքանչյուր շեմի համար՝ միմյանցից մեկուսացված:

Եվ հիմա, մտածելով, թե ինչպես իրականացնել այս ամենը նվազագույն ծախսերով, ես ավտոմատ կերպով ուղղում եմ վիճակի ստուգումը

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

մասին

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

Ես նորից անցկացնում եմ թեստերը և դադարում եմ որևէ բան հասկանալ :)

Կատարման վրա ծախսված ժամանակը սկսում է տարբերվել ոչ թե տոկոսներով/կոտորակներով, այլ 10..15%-ով։Ես արագ ավելացնում եմ ևս 2 թեստ.

		
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
}

Ես գործարկում եմ այն ​​և ստանում եմ այս նկարը.զանգվածի նախնական հզորությունը՝ 100000000

առավելագույն շեմ՝ 128
maxEven Dividing արդյունք՝ 126 տևողություն 116.0066 մս
maxEvenDividing2 արդյունք՝ 126 տևողություն 79.0045 մվ
maxEvenConjunction արդյունք՝ 126 տևողություն 114.0065 մվ
maxEvenConjunction2 արդյունք՝ 126 տևողություն 83.0048 մս

առավելագույն շեմ՝ 256
maxEven Dividing արդյունք՝ 254 տևողություն 111.0063 մս
maxEvenDividing2 արդյունք՝ 254 տևողություն 77.0044 մվ
maxEvenConjunction արդյունք՝ 254 տևողություն 110.0063 մվ
maxEvenConjunction2 արդյունք՝ 254 տևողություն 80.0046 մս

առավելագույն շեմ՝ 512
maxEven Dividing արդյունք՝ 510 տևողություն 114.0066 մս
maxEvenDividing2 արդյունք՝ 510 տևողություն 80.0045 մվ
maxEvenConjunction արդյունք՝ 510 տևողություն 110.0063 մվ
maxEvenConjunction2 արդյունք՝ 510 տևողություն 80.0046 մս

առավելագույն շեմ՝ 1024
maxEven Dividing արդյունք՝ 1022 տևողություն 109.0063 մս
maxEvenDividing2 արդյունք՝ 1022 տևողություն 77.0044 մվ
maxEvenConjunction արդյունք՝ 1022 տևողություն 111.0063 մվ
maxEvenConjunction2 արդյունք՝ 1022 տևողություն 81.0047 մս

առավելագույն շեմ՝ 2048
maxEven Dividing արդյունք՝ 2046 տևողություն 114.0065 մս
maxEvenDividing2 արդյունք՝ 2046 տևողություն 79.0045 մվ
maxEvenConjunction արդյունք՝ 2046 տևողություն 113.0065 մվ
maxEvenConjunction2 արդյունք՝ 2046 տևողություն 81.0046 մս

առավելագույն շեմ՝ 4096
maxEven Dividing արդյունք՝ 4094 տևողություն 114.0065 մս
maxEvenDividing2 արդյունք՝ 4094 տևողություն 80.0046 մվ
maxEvenConjunction արդյունք՝ 4094 տևողություն 111.0063 մվ
maxEvenConjunction2 արդյունք՝ 4094 տևողություն 78.0045 մս

առավելագույն շեմ՝ 8192
maxEven Dividing արդյունք՝ 8190 տևողություն 107.0062 մս
maxEvenDividing2 արդյունք՝ 8190 տևողություն 77.0044 մվ
maxEvenConjunction արդյունք՝ 8190 տևողություն 111.0063 մվ
maxEvenConjunction2 արդյունք՝ 8190 տևողություն 77.0044 մս

առավելագույն շեմ՝ 16384
maxEven Dividing արդյունք՝ 16382 տևողություն 109.0063 մս
maxEvenDividing2 արդյունք՝ 16382 տևողություն 77.0044 մվ
maxEvenConjunction արդյունք՝ 16382 տևողություն 108.0062 մվ
maxEvenConjunction2 արդյունք՝ 16382 տևողություն 77.0044 մս

առավելագույն շեմ՝ 32768
maxEven Dividing արդյունք՝ 32766 տևողություն 112.0064 մս
maxEvenDividing2 արդյունք՝ 32766 տևողություն 77.0044 մվ
maxEvenConjunction արդյունք՝ 32766 տևողություն 109.0062 մվ
maxEvenConjunction2 արդյունք՝ 32766 տևողություն 78.0045 մս

առավելագույն շեմ՝ 65536
maxEven Dividing արդյունք՝ 65534 տևողություն 109.0062 մս
maxEvenDividing2 արդյունք՝ 65534 տևողություն 75.0043 մվ
maxEvenConjunction արդյունք՝ 65534 տևողություն 109.0063 մվ
maxEvenConjunction2 արդյունք՝ 65534 տևողություն 79.0045 մս

առավելագույն շեմ՝ 131072
maxEven Dividing արդյունք՝ 131070 տևողություն 108.0061 մս
maxEvenDividing2 արդյունք՝ 131070 տևողություն 76.0044 մվ
maxEvenConjunction արդյունք՝ 131070 տևողություն 110.0063 մվ
maxEvenConjunction2 արդյունք՝ 131070 տևողություն 80.0046 մս

առավելագույն շեմ՝ 262144
maxEven Dividing արդյունք՝ 262142 տևողություն 110.0063 մս
maxEvenDividing2 արդյունք՝ 262142 տևողություն 76.0044 մվ
maxEvenConjunction արդյունք՝ 262142 տևողություն 107.0061 մվ
maxEvenConjunction2 արդյունք՝ 262142 տևողություն 78.0044 մս

առավելագույն շեմ՝ 524288
maxEven Dividing արդյունք՝ 524286 տևողություն 109.0062 մս
maxEvenDividing2 արդյունք՝ 524286 տևողություն 78.0045 մվ
maxEvenConjunction արդյունք՝ 524286 տևողություն 109.0062 մվ
maxEvenConjunction2 արդյունք՝ 524286 տևողություն 80.0046 մս

առավելագույն շեմ՝ 1048576
maxEven Dividing արդյունք՝ 1048574 տևողություն 109.0063 մս
maxEvenDividing2 արդյունք՝ 1048574 տևողություն 80.0045 մվ
maxEvenConjunction արդյունք՝ 1048574 տևողություն 114.0066 մվ
maxEvenConjunction2 արդյունք՝ 1048574 տևողություն 78.0044 մս

առավելագույն շեմ՝ 2097152
maxEven Dividing արդյունք՝ 2097150 տևողություն 111.0064 մս
maxEvenDividing2 արդյունք՝ 2097150 տևողություն 79.0045 մվ
maxEvenConjunction արդյունք՝ 2097150 տևողություն 112.0064 մվ
maxEvenConjunction2 արդյունք՝ 2097150 տևողություն 77.0044 մս

առավելագույն շեմ՝ 4194304
maxEven Dividing արդյունք՝ 4194302 տևողություն 111.0063 մս
maxEvenDividing2 արդյունք՝ 4194302 տևողություն 78.0045 մվ
maxEvenConjunction արդյունք՝ 4194302 տևողություն 111.0063 մվ
maxEvenConjunction2 արդյունք՝ 4194302 տևողություն 77.0044 մս

առավելագույն շեմ՝ 8388608
maxEven Dividing արդյունք՝ 8388606 տևողություն 109.0062 մս
maxEvenDividing2 արդյունք՝ 8388606 տևողություն 78.0045 մվ
maxEvenConjunction արդյունք՝ 8388606 տևողություն 114.0065 մվ
maxEvenConjunction2 արդյունք՝ 8388606 տևողություն 78.0045 մս

առավելագույն շեմ՝ 16777216
maxEven Dividing արդյունք՝ 16777214 տևողություն 109.0062 մս
maxEvenDividing2 արդյունք՝ 16777214 տևողություն 77.0044 մվ
maxEvenConjunction արդյունք՝ 16777214 տևողություն 109.0063 մվ
maxEvenConjunction2 արդյունք՝ 16777214 տևողություն 77.0044 մս

առավելագույն շեմ՝ 33554432
maxEven Dividing արդյունք՝ 33554430 տևողություն 113.0065 մս
maxEvenDividing2 արդյունք՝ 33554430 տևողություն 78.0045 մվ
maxEvenConjunction արդյունք՝ 33554430 տևողություն 110.0063 մվ
maxEvenConjunction2 արդյունք՝ 33554430 տևողություն 80.0045 մս

առավելագույն շեմ՝ 67108864
maxEven Dividing արդյունք՝ 67108860 տևողություն 112.0064 մս
maxEvenDividing2 արդյունք՝ 67108860 տևողություն 77.0044 մվ
maxEvenConjunction արդյունք՝ 67108860 տևողություն 112.0064 մվ
maxEvenConjunction2 արդյունք՝ 67108860 տևողություն 80.0046 մս

առավելագույն շեմ՝ 134217728
maxEven Dividing արդյունք՝ 134217726 տևողություն 109.0063 մս
maxEvenDividing2 արդյունք՝ 134217726 տևողություն 78.0044 մվ
maxEvenConjunction արդյունք՝ 134217726 տևողություն 114.0065 մվ
maxEvenConjunction2 արդյունք՝ 134217726 տևողություն 81.0047 մս

առավելագույն շեմ՝ 268435456
maxEven Dividing արդյունք՝ 268435446 տևողություն 111.0064 մս
maxEvenDividing2 արդյունք՝ 268435446 տևողություն 79.0045 մվ
maxEvenConjunction արդյունք՝ 268435446 տևողություն 114.0065 մվ
maxEvenConjunction2 արդյունք՝ 268435446 տևողություն 79.0045 մս

առավելագույն շեմ՝ 536870912
maxEven Dividing արդյունք՝ 536870910 տևողություն 107.0062 մս
maxEvenDividing2 արդյունք՝ 536870910 տևողություն 76.0043 մվ
maxEvenConjunction արդյունք՝ 536870910 տևողություն 109.0062 մվ
maxEvenConjunction2 արդյունք՝ 536870910 տևողություն 80.0046 մս

Ես չկարողացա հստակ բացատրություն գտնել, թե ինչու Go կոմպիլյատորը չի օպտիմալացնում կոդը և միշտ ստուգում է երկրորդ պայմանը, նույնիսկ եթե առաջինը կեղծ է: Կամ գուցե իմ աչքերը պարզապես մշուշոտ են, և ես որևէ ակնհայտ սխալ չեմ տեսնում: Կամ պետք է ինչ-որ հատուկ հրահանգներ տրամադրել կոմպիլյատորին: Ուրախ կլինեմ խելամիտ մեկնաբանությունների համար։

PS: Այո, պարզապես զվարճանալու համար, ես անցկացրի նմանատիպ թեստեր Java 5-ի և Java 7/8-ի վրա - ամեն ինչ պարզ է, կատարման ժամանակը նույնն է:

Source: www.habr.com

Добавить комментарий