Aðstæður í Go og einkenni þeirra

Telur þú að þessir tveir valkostir til að prófa aðstæður inni í lykkju séu jafngildir í frammistöðu?

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


Þetta byrjaði allt með „heilahitun“; ég þurfti að gefa dæmi um ákjósanlega leit að stærstu sléttu tölunni í heiltölum [-x....x]. Ég var að velta því fyrir mér hversu miklu betri árangur væri ef ég notaði röklega margföldun með 1 til að komast að því hvort tala er slétt eða ekki.


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

Forritunarreynsla mín í Go er ekki mjög mikil, rúmlega eitt og hálft ár, ég notaði hana, þó oft, en eingöngu í nytjaskyni (tja, kannski fyrir utan eitt verkefni sem tengist mikið álagi http þjónustu), svo ég byrjaði á því. Opnaðu GoLand og skrifaðu einfalt próf


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
}

Við fáum niðurstöðu sem sýnir að því hærri sem þröskuldurinn er, því oftar koma fram sveiflur í frammistöðu.

Bera samanmax 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

Það er ljóst að í þessu tilviki, fyrir mismunandi þröskulda, erum við með mismunandi sett af prófunargögnum, örgjörvaálagið (á i5-2540M fartölvunni minni) er breytilegt um 20..30%, minnið sem er upptekið af forritinu sem keyrir frá GoLand er að meðaltali um 813MB - þetta hefur einnig áhrif á áreiðanleika niðurstöðunnar, þú þarft að vista prófunartilvik á disknum og keyra öll próf fyrir hvern þröskuld í einangrun frá hvort öðru.

Og nú, þegar ég hugsa um hvernig eigi að útfæra þetta allt með lágmarkskostnaði, leiðrétti ég sjálfkrafa ástandsskoðunina

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

á

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

Ég keyri prófin aftur... og ég hætti að skilja neitt :)

Tíminn sem fer í framkvæmd byrjar ekki lengur að vera mismunandi eftir prósentum/hlutum úr prósenti, heldur um 10..15%. Ég bæti fljótt við 2 prófum í viðbót:

		
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
}

Ég keyri það og fæ þessa mynd:Upphafsfjöldi getu: 100000000

hámarksþröskuldur: 128
maxEvenDeiling niðurstaða: 126 lengd 116.0066ms
maxEvenDividing2 niðurstaða: 126 lengd 79.0045ms
maxEvenConjunction niðurstaða: 126 lengd 114.0065ms
maxEvenConjunction2 niðurstaða: 126 lengd 83.0048ms

hámarksþröskuldur: 256
maxEvenDeiling niðurstaða: 254 lengd 111.0063ms
maxEvenDividing2 niðurstaða: 254 lengd 77.0044ms
maxEvenConjunction niðurstaða: 254 lengd 110.0063ms
maxEvenConjunction2 niðurstaða: 254 lengd 80.0046ms

hámarksþröskuldur: 512
maxEvenDeiling niðurstaða: 510 lengd 114.0066ms
maxEvenDividing2 niðurstaða: 510 lengd 80.0045ms
maxEvenConjunction niðurstaða: 510 lengd 110.0063ms
maxEvenConjunction2 niðurstaða: 510 lengd 80.0046ms

hámarksþröskuldur: 1024
maxEvenDeiling niðurstaða: 1022 lengd 109.0063ms
maxEvenDividing2 niðurstaða: 1022 lengd 77.0044ms
maxEvenConjunction niðurstaða: 1022 lengd 111.0063ms
maxEvenConjunction2 niðurstaða: 1022 lengd 81.0047ms

hámarksþröskuldur: 2048
maxEvenDeiling niðurstaða: 2046 lengd 114.0065ms
maxEvenDividing2 niðurstaða: 2046 lengd 79.0045ms
maxEvenConjunction niðurstaða: 2046 lengd 113.0065ms
maxEvenConjunction2 niðurstaða: 2046 lengd 81.0046ms

hámarksþröskuldur: 4096
maxEvenDeiling niðurstaða: 4094 lengd 114.0065ms
maxEvenDividing2 niðurstaða: 4094 lengd 80.0046ms
maxEvenConjunction niðurstaða: 4094 lengd 111.0063ms
maxEvenConjunction2 niðurstaða: 4094 lengd 78.0045ms

hámarksþröskuldur: 8192
maxEvenDeiling niðurstaða: 8190 lengd 107.0062ms
maxEvenDividing2 niðurstaða: 8190 lengd 77.0044ms
maxEvenConjunction niðurstaða: 8190 lengd 111.0063ms
maxEvenConjunction2 niðurstaða: 8190 lengd 77.0044ms

hámarksþröskuldur: 16384
maxEvenDeiling niðurstaða: 16382 lengd 109.0063ms
maxEvenDividing2 niðurstaða: 16382 lengd 77.0044ms
maxEvenConjunction niðurstaða: 16382 lengd 108.0062ms
maxEvenConjunction2 niðurstaða: 16382 lengd 77.0044ms

hámarksþröskuldur: 32768
maxEvenDeiling niðurstaða: 32766 lengd 112.0064ms
maxEvenDividing2 niðurstaða: 32766 lengd 77.0044ms
maxEvenConjunction niðurstaða: 32766 lengd 109.0062ms
maxEvenConjunction2 niðurstaða: 32766 lengd 78.0045ms

hámarksþröskuldur: 65536
maxEvenDeiling niðurstaða: 65534 lengd 109.0062ms
maxEvenDividing2 niðurstaða: 65534 lengd 75.0043ms
maxEvenConjunction niðurstaða: 65534 lengd 109.0063ms
maxEvenConjunction2 niðurstaða: 65534 lengd 79.0045ms

hámarksþröskuldur: 131072
maxEvenDeiling niðurstaða: 131070 lengd 108.0061ms
maxEvenDividing2 niðurstaða: 131070 lengd 76.0044ms
maxEvenConjunction niðurstaða: 131070 lengd 110.0063ms
maxEvenConjunction2 niðurstaða: 131070 lengd 80.0046ms

hámarksþröskuldur: 262144
maxEvenDeiling niðurstaða: 262142 lengd 110.0063ms
maxEvenDividing2 niðurstaða: 262142 lengd 76.0044ms
maxEvenConjunction niðurstaða: 262142 lengd 107.0061ms
maxEvenConjunction2 niðurstaða: 262142 lengd 78.0044ms

hámarksþröskuldur: 524288
maxEvenDeiling niðurstaða: 524286 lengd 109.0062ms
maxEvenDividing2 niðurstaða: 524286 lengd 78.0045ms
maxEvenConjunction niðurstaða: 524286 lengd 109.0062ms
maxEvenConjunction2 niðurstaða: 524286 lengd 80.0046ms

hámarksþröskuldur: 1048576
maxEvenDeiling niðurstaða: 1048574 lengd 109.0063ms
maxEvenDividing2 niðurstaða: 1048574 lengd 80.0045ms
maxEvenConjunction niðurstaða: 1048574 lengd 114.0066ms
maxEvenConjunction2 niðurstaða: 1048574 lengd 78.0044ms

hámarksþröskuldur: 2097152
maxEvenDeiling niðurstaða: 2097150 lengd 111.0064ms
maxEvenDividing2 niðurstaða: 2097150 lengd 79.0045ms
maxEvenConjunction niðurstaða: 2097150 lengd 112.0064ms
maxEvenConjunction2 niðurstaða: 2097150 lengd 77.0044ms

hámarksþröskuldur: 4194304
maxEvenDeiling niðurstaða: 4194302 lengd 111.0063ms
maxEvenDividing2 niðurstaða: 4194302 lengd 78.0045ms
maxEvenConjunction niðurstaða: 4194302 lengd 111.0063ms
maxEvenConjunction2 niðurstaða: 4194302 lengd 77.0044ms

hámarksþröskuldur: 8388608
maxEvenDeiling niðurstaða: 8388606 lengd 109.0062ms
maxEvenDividing2 niðurstaða: 8388606 lengd 78.0045ms
maxEvenConjunction niðurstaða: 8388606 lengd 114.0065ms
maxEvenConjunction2 niðurstaða: 8388606 lengd 78.0045ms

hámarksþröskuldur: 16777216
maxEvenDeiling niðurstaða: 16777214 lengd 109.0062ms
maxEvenDividing2 niðurstaða: 16777214 lengd 77.0044ms
maxEvenConjunction niðurstaða: 16777214 lengd 109.0063ms
maxEvenConjunction2 niðurstaða: 16777214 lengd 77.0044ms

hámarksþröskuldur: 33554432
maxEvenDeiling niðurstaða: 33554430 lengd 113.0065ms
maxEvenDividing2 niðurstaða: 33554430 lengd 78.0045ms
maxEvenConjunction niðurstaða: 33554430 lengd 110.0063ms
maxEvenConjunction2 niðurstaða: 33554430 lengd 80.0045ms

hámarksþröskuldur: 67108864
maxEvenDeiling niðurstaða: 67108860 lengd 112.0064ms
maxEvenDividing2 niðurstaða: 67108860 lengd 77.0044ms
maxEvenConjunction niðurstaða: 67108860 lengd 112.0064ms
maxEvenConjunction2 niðurstaða: 67108860 lengd 80.0046ms

hámarksþröskuldur: 134217728
maxEvenDeiling niðurstaða: 134217726 lengd 109.0063ms
maxEvenDividing2 niðurstaða: 134217726 lengd 78.0044ms
maxEvenConjunction niðurstaða: 134217726 lengd 114.0065ms
maxEvenConjunction2 niðurstaða: 134217726 lengd 81.0047ms

hámarksþröskuldur: 268435456
maxEvenDeiling niðurstaða: 268435446 lengd 111.0064ms
maxEvenDividing2 niðurstaða: 268435446 lengd 79.0045ms
maxEvenConjunction niðurstaða: 268435446 lengd 114.0065ms
maxEvenConjunction2 niðurstaða: 268435446 lengd 79.0045ms

hámarksþröskuldur: 536870912
maxEvenDeiling niðurstaða: 536870910 lengd 107.0062ms
maxEvenDividing2 niðurstaða: 536870910 lengd 76.0043ms
maxEvenConjunction niðurstaða: 536870910 lengd 109.0062ms
maxEvenConjunction2 niðurstaða: 536870910 lengd 80.0046ms

Ég gat ekki fundið skýra skýringu á því hvers vegna Go þýðandinn fínstillir ekki kóðann og athugar alltaf annað skilyrðið, jafnvel þótt það fyrsta sé rangt. Eða eru augun kannski bara óskýr og ég sé engin augljós mistök? Eða þarftu að gefa þýðandanum einhverjar sérstakar leiðbeiningar? Ég væri ánægður með skynsamlegar athugasemdir.

PS: Já, bara til gamans þá keyrði ég svipuð próf á Java 5 og Java 7/8 - allt er á hreinu, framkvæmdartíminn er sá sami.

Heimild: www.habr.com

Bæta við athugasemd