Apstākļi Go un to dīvainības

Vai, jūsuprāt, šīs divas iespējas cilpas apstākļu testēšanai ir līdzvērtīgas veiktspējai?

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


Viss sākās ar “smadzeņu iesildīšanu”; man bija jāsniedz piemērs optimālai lielākā pāra skaitļa meklēšanai veselu skaitļu masīvā [-x....x]. Es domāju, cik daudz labāka veiktspēja būtu, ja es izmantotu loģisko reizināšanu ar 1, lai noskaidrotu, vai skaitlis ir pāra vai nē.


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

Mana programmēšanas pieredze Go nav īpaši plaša, tikai nedaudz vairāk par pusotru gadu, es to izmantoju, lai gan bieži, bet tīri utilitāriem nolūkiem (nu, varbūt izņemot vienu projektu, kas saistīts ar augstas slodzes http servisu), tāpēc es sākās ar to. Atveriet GoLand un uzrakstiet vienkāršu testu


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
}

Iegūstam rezultātu, kas parāda, jo augstāks slieksnis, jo biežāk parādās veiktspējas svārstības.

Salīdzinātmax threshold: 128
maxEvenDividing result: 126 duration 116.0067ms
maxEvenConjunction result: 126 duration 116.0066ms

maksimālais slieksnis: 16384
maxEvenDividing rezultāts: 16382 ilgums 115.0066 ms
maxEvenConjunction rezultāts: 16382 ilgums 111.0064 ms

......

maksimālais slieksnis: 8388608
maxEvenDividing rezultāts: 8388606 ilgums 109.0063 ms
maxEvenConjunction rezultāts: 8388606 ilgums 109.0062 ms

maksimālais slieksnis: 16777216
maxEvenDividing rezultāts: 16777214 ilgums 108.0062 ms
maxEvenConjunction rezultāts: 16777214 ilgums 109.0062 ms

maksimālais slieksnis: 33554432
maxEvenDividing rezultāts: 33554430 ilgums 114.0066 ms
maxEvenConjunction rezultāts: 33554430 ilgums 110.0063 ms

maksimālais slieksnis: 67108864
maxEvenDividing rezultāts: 67108860 ilgums 111.0064 ms
maxEvenConjunction rezultāts: 67108860 ilgums 109.0062 ms

maksimālais slieksnis: 134217728
maxEvenDividing rezultāts: 134217726 ilgums 108.0062 ms
maxEvenConjunction rezultāts: 134217726 ilgums 109.0063 ms

maksimālais slieksnis: 268435456
maxEvenDividing rezultāts: 268435446 ilgums 111.0063 ms
maxEvenConjunction rezultāts: 268435446 ilgums 110.0063 ms

Ir skaidrs, ka šajā gadījumā dažādiem sliekšņiem mums ir dažādas testa datu kopas, procesora slodze (manā klēpjdatorā i5-2540M) svārstās ap 20..30%, atmiņa, ko aizņem lietojumprogramma, kas darbojas no GoLand, ir vidēji. apmēram 813 MB - tas ietekmē arī rezultāta ticamību, jums ir jāsaglabā testa gadījumi diskā un jāveic visi testi katram slieksnim atsevišķi viens no otra.

Un tagad, domājot, kā to visu īstenot ar minimālām izmaksām, automātiski laboju stāvokļa pārbaudi

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

par

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

Izpildu testus vēlreiz... un vairs neko nesaprotu :)

Izpildei pavadītais laiks sāk atšķirties nevis par procentiem/procentu daļām, bet par 10..15%.Ātri pievienoju vēl 2 testus:

		
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
}

Es to palaižu un iegūstu šo attēlu:sākotnējā masīva ietilpība: 100000000

maksimālais slieksnis: 128
maxEvenDividing rezultāts: 126 ilgums 116.0066 ms
maxEvenDividing2 rezultāts: 126 ilgums 79.0045 ms
maxEvenConjunction rezultāts: 126 ilgums 114.0065 ms
maxEvenConjunction2 rezultāts: 126 ilgums 83.0048 ms

maksimālais slieksnis: 256
maxEvenDividing rezultāts: 254 ilgums 111.0063 ms
maxEvenDividing2 rezultāts: 254 ilgums 77.0044 ms
maxEvenConjunction rezultāts: 254 ilgums 110.0063 ms
maxEvenConjunction2 rezultāts: 254 ilgums 80.0046 ms

maksimālais slieksnis: 512
maxEvenDividing rezultāts: 510 ilgums 114.0066 ms
maxEvenDividing2 rezultāts: 510 ilgums 80.0045 ms
maxEvenConjunction rezultāts: 510 ilgums 110.0063 ms
maxEvenConjunction2 rezultāts: 510 ilgums 80.0046 ms

maksimālais slieksnis: 1024
maxEvenDividing rezultāts: 1022 ilgums 109.0063 ms
maxEvenDividing2 rezultāts: 1022 ilgums 77.0044 ms
maxEvenConjunction rezultāts: 1022 ilgums 111.0063 ms
maxEvenConjunction2 rezultāts: 1022 ilgums 81.0047 ms

maksimālais slieksnis: 2048
maxEvenDividing rezultāts: 2046 ilgums 114.0065 ms
maxEvenDividing2 rezultāts: 2046 ilgums 79.0045 ms
maxEvenConjunction rezultāts: 2046 ilgums 113.0065 ms
maxEvenConjunction2 rezultāts: 2046 ilgums 81.0046 ms

maksimālais slieksnis: 4096
maxEvenDividing rezultāts: 4094 ilgums 114.0065 ms
maxEvenDividing2 rezultāts: 4094 ilgums 80.0046 ms
maxEvenConjunction rezultāts: 4094 ilgums 111.0063 ms
maxEvenConjunction2 rezultāts: 4094 ilgums 78.0045 ms

maksimālais slieksnis: 8192
maxEvenDividing rezultāts: 8190 ilgums 107.0062 ms
maxEvenDividing2 rezultāts: 8190 ilgums 77.0044 ms
maxEvenConjunction rezultāts: 8190 ilgums 111.0063 ms
maxEvenConjunction2 rezultāts: 8190 ilgums 77.0044 ms

maksimālais slieksnis: 16384
maxEvenDividing rezultāts: 16382 ilgums 109.0063 ms
maxEvenDividing2 rezultāts: 16382 ilgums 77.0044 ms
maxEvenConjunction rezultāts: 16382 ilgums 108.0062 ms
maxEvenConjunction2 rezultāts: 16382 ilgums 77.0044 ms

maksimālais slieksnis: 32768
maxEvenDividing rezultāts: 32766 ilgums 112.0064 ms
maxEvenDividing2 rezultāts: 32766 ilgums 77.0044 ms
maxEvenConjunction rezultāts: 32766 ilgums 109.0062 ms
maxEvenConjunction2 rezultāts: 32766 ilgums 78.0045 ms

maksimālais slieksnis: 65536
maxEvenDividing rezultāts: 65534 ilgums 109.0062 ms
maxEvenDividing2 rezultāts: 65534 ilgums 75.0043 ms
maxEvenConjunction rezultāts: 65534 ilgums 109.0063 ms
maxEvenConjunction2 rezultāts: 65534 ilgums 79.0045 ms

maksimālais slieksnis: 131072
maxEvenDividing rezultāts: 131070 ilgums 108.0061 ms
maxEvenDividing2 rezultāts: 131070 ilgums 76.0044 ms
maxEvenConjunction rezultāts: 131070 ilgums 110.0063 ms
maxEvenConjunction2 rezultāts: 131070 ilgums 80.0046 ms

maksimālais slieksnis: 262144
maxEvenDividing rezultāts: 262142 ilgums 110.0063 ms
maxEvenDividing2 rezultāts: 262142 ilgums 76.0044 ms
maxEvenConjunction rezultāts: 262142 ilgums 107.0061 ms
maxEvenConjunction2 rezultāts: 262142 ilgums 78.0044 ms

maksimālais slieksnis: 524288
maxEvenDividing rezultāts: 524286 ilgums 109.0062 ms
maxEvenDividing2 rezultāts: 524286 ilgums 78.0045 ms
maxEvenConjunction rezultāts: 524286 ilgums 109.0062 ms
maxEvenConjunction2 rezultāts: 524286 ilgums 80.0046 ms

maksimālais slieksnis: 1048576
maxEvenDividing rezultāts: 1048574 ilgums 109.0063 ms
maxEvenDividing2 rezultāts: 1048574 ilgums 80.0045 ms
maxEvenConjunction rezultāts: 1048574 ilgums 114.0066 ms
maxEvenConjunction2 rezultāts: 1048574 ilgums 78.0044 ms

maksimālais slieksnis: 2097152
maxEvenDividing rezultāts: 2097150 ilgums 111.0064 ms
maxEvenDividing2 rezultāts: 2097150 ilgums 79.0045 ms
maxEvenConjunction rezultāts: 2097150 ilgums 112.0064 ms
maxEvenConjunction2 rezultāts: 2097150 ilgums 77.0044 ms

maksimālais slieksnis: 4194304
maxEvenDividing rezultāts: 4194302 ilgums 111.0063 ms
maxEvenDividing2 rezultāts: 4194302 ilgums 78.0045 ms
maxEvenConjunction rezultāts: 4194302 ilgums 111.0063 ms
maxEvenConjunction2 rezultāts: 4194302 ilgums 77.0044 ms

maksimālais slieksnis: 8388608
maxEvenDividing rezultāts: 8388606 ilgums 109.0062 ms
maxEvenDividing2 rezultāts: 8388606 ilgums 78.0045 ms
maxEvenConjunction rezultāts: 8388606 ilgums 114.0065 ms
maxEvenConjunction2 rezultāts: 8388606 ilgums 78.0045 ms

maksimālais slieksnis: 16777216
maxEvenDividing rezultāts: 16777214 ilgums 109.0062 ms
maxEvenDividing2 rezultāts: 16777214 ilgums 77.0044 ms
maxEvenConjunction rezultāts: 16777214 ilgums 109.0063 ms
maxEvenConjunction2 rezultāts: 16777214 ilgums 77.0044 ms

maksimālais slieksnis: 33554432
maxEvenDividing rezultāts: 33554430 ilgums 113.0065 ms
maxEvenDividing2 rezultāts: 33554430 ilgums 78.0045 ms
maxEvenConjunction rezultāts: 33554430 ilgums 110.0063 ms
maxEvenConjunction2 rezultāts: 33554430 ilgums 80.0045 ms

maksimālais slieksnis: 67108864
maxEvenDividing rezultāts: 67108860 ilgums 112.0064 ms
maxEvenDividing2 rezultāts: 67108860 ilgums 77.0044 ms
maxEvenConjunction rezultāts: 67108860 ilgums 112.0064 ms
maxEvenConjunction2 rezultāts: 67108860 ilgums 80.0046 ms

maksimālais slieksnis: 134217728
maxEvenDividing rezultāts: 134217726 ilgums 109.0063 ms
maxEvenDividing2 rezultāts: 134217726 ilgums 78.0044 ms
maxEvenConjunction rezultāts: 134217726 ilgums 114.0065 ms
maxEvenConjunction2 rezultāts: 134217726 ilgums 81.0047 ms

maksimālais slieksnis: 268435456
maxEvenDividing rezultāts: 268435446 ilgums 111.0064 ms
maxEvenDividing2 rezultāts: 268435446 ilgums 79.0045 ms
maxEvenConjunction rezultāts: 268435446 ilgums 114.0065 ms
maxEvenConjunction2 rezultāts: 268435446 ilgums 79.0045 ms

maksimālais slieksnis: 536870912
maxEvenDividing rezultāts: 536870910 ilgums 107.0062 ms
maxEvenDividing2 rezultāts: 536870910 ilgums 76.0043 ms
maxEvenConjunction rezultāts: 536870910 ilgums 109.0062 ms
maxEvenConjunction2 rezultāts: 536870910 ilgums 80.0046 ms

Es nevarēju atrast skaidru skaidrojumu, kāpēc Go kompilators neoptimizē kodu un vienmēr pārbauda otro nosacījumu, pat ja pirmais ir nepatiess. Vai varbūt manas acis ir vienkārši izplūdušas un es neredzu nekādu acīmredzamu kļūdu? Vai arī jums ir jāsniedz daži īpaši norādījumi kompilatoram? Priecāšos par saprātīgiem komentāriem.

PS: Jā, sava prieka pēc, es veica līdzīgus testus uz Java 5 un Java 7/8 - viss skaidrs, izpildes laiks ir vienāds.

Avots: www.habr.com

Iegādājieties uzticamu mitināšanu vietnēm ar DDoS aizsardzību, VPS VDS serveriem 🔥 Iegādājieties uzticamu tīmekļa vietņu mitināšanu ar DDoS aizsardzību, VPS VDS serveriem | ProHoster