Kas te arvate, et need kaks tingimuste kontrollimise varianti on jõudluse poolest samaväärsed?
if a > b && c*2 > d {
....
}
// ja
if a d {
....
}
Kõik algas "aju soojendusest", pidi tooma näiteks optimaalse otsingu täisarvude massiivist [-x….x] suurima paarisarvu kohta. Mind hakkas huvitama, kui palju kõrgem on jõudlus, kui paarisuse määramiseks kasutada loogilist korrutamist 1-ga.
//у четных чисел последний бит всегда равен 0
value & 1 == 0
//vs классический метод
value % 2 == 0
Minu kogemus Go programmeerimises ei ole väga suur, veidi üle pooleteise aasta, olen seda kasutanud, kuigi tihti, puhtalt utilitaarsetel eesmärkidel (võib-olla välja arvatud üks projekt, mis on seotud suure koormusega http teenusega), seega alustasin ma just sellest. Avame GoLand'i ja kirjutame lihtsa testi.
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("algne massiivi maht: " + fmt.Sprint(size))
var maxValue int32
// Väärame numbrite vahemikku minimaalset
// kuni maksimaalseni. Mida väiksem vahemik, seda rohkem
// protsessoriaega kulub praeguse arvu võrdlemiseks,
// varem leitud ja vastupidi
for maxValue = 128; maxValue Saame tulemuse, kus on näha, et mida suurem on künnis, seda sagedamini esinevad jõudluse kõikumised.
Võrdlemaksimaalne lävi: 128
maxEvenJagamine tulemus: 126 kestus 116.0067ms
maxEvenKooskõla tulemus: 126 kestus 116.0066ms
max künnis: 16384
maxEvenDividing tulemus: 16382 kestus 115.0066ms
maxEvenConjunction tulemus: 16382 kestus 111.0064ms
......
max künnis: 8388608
maxEvenDividing tulemus: 8388606 kestus 109.0063ms
maxEvenConjunction tulemus: 8388606 kestus 109.0062ms
max künnis: 16777216
maxEvenDividing tulemus: 16777214 kestus 108.0062ms
maxEvenConjunction tulemus: 16777214 kestus 109.0062ms
max künnis: 33554432
maxEvenDividing tulemus: 33554430 kestus 114.0066ms
maxEvenConjunction tulemus: 33554430 kestus 110.0063ms
max künnis: 67108864
maxEvenDividing tulemus: 67108860 kestus 111.0064ms
maxEvenConjunction tulemus: 67108860 kestus 109.0062ms
max künnis: 134217728
maxEvenDividing tulemus: 134217726 kestus 108.0062ms
maxEvenConjunction tulemus: 134217726 kestus 109.0063ms
max künnis: 268435456
maxEvenDividing tulemus: 268435446 kestus 111.0063ms
maxEvenConjunction tulemus: 268435446 kestus 110.0063ms
On selge, et antud juhul, erinevate künniste puhul, on meil erinevad testikomplektid, protsessori koormus (mu computeris i5-2540M) kõigub umbes 20..30% vahel, GoLand'ist käivitav rakendus kasutab keskmiselt umbes 813MB — see mõjutab ka tulemuse usaldusväärsust, tuleb rakendada testikomplektide salvestamist kettale ja läbi viia kõik testid iga künnise jaoks eraldiseisvalt.
Ja mõeldes sellele, kuidas minimaalseid kulutusi teha, parandangi ma automaatselt tingimuse kontrolli
if value > current && value&1 == 0 {
current = value
}
. Tundub, et
if value <= current {
continue;
}
if value&1 == 0 {
current = value
}
käivitan testid uuesti... ja lõpetan kõikjale segadusse jäämise 🙂
Aeg, mis kulub täitmisele, hakkab eristuma mitte protsentide / osade kaupa, vaid 10..15% võrra. Kiiresti kirjutan juurde veel 2 testi:
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
}
käivitan ja saan sellise pildi:algne massiivi maht: 100000000
maksimaalne lävi: 128
maxEvenDividing tulemus: 126 kestus 116.0066ms
maxEvenDividing2 tulemus: 126 kestus 79.0045ms
maxEvenConjunction tulemus: 126 kestus 114.0065ms
maxEvenConjunction2 tulemus: 126 kestus 83.0048ms
max künnis: 256
maxEvenDividing tulemus: 254 kestus 111.0063ms
maxEvenDividing2 tulemus: 254 kestus 77.0044ms
maxEvenConjunction tulemus: 254 kestus 110.0063ms
maxEvenConjunction2 tulemus: 254 kestus 80.0046ms
max künnis: 512
maxEvenDividing tulemus: 510 kestus 114.0066ms
maxEvenDividing2 tulemus: 510 kestus 80.0045ms
maxEvenConjunction tulemus: 510 kestus 110.0063ms
maxEvenConjunction2 tulemus: 510 kestus 80.0046ms
max künnis: 1024
maxEvenDividing tulemus: 1022 kestus 109.0063ms
maxEvenDividing2 tulemus: 1022 kestus 77.0044ms
maxEvenConjunction tulemus: 1022 kestus 111.0063ms
maxEvenConjunction2 tulemus: 1022 kestus 81.0047ms
max künnis: 2048
maxEvenDividing tulemus: 2046 kestus 114.0065ms
maxEvenDividing2 tulemus: 2046 kestus 79.0045ms
maxEvenConjunction tulemus: 2046 kestus 113.0065ms
maxEvenConjunction2 tulemus: 2046 kestus 81.0046ms
max piir: 4096
maxEvenDividing tulemus: 4094 kestus 114.0065ms
maxEvenDividing2 tulemus: 4094 kestus 80.0046ms
maxEvenConjunction tulemus: 4094 kestus 111.0063ms
maxEvenConjunction2 tulemus: 4094 kestus 78.0045ms
max piir: 8192
maxEvenDividing tulemus: 8190 kestus 107.0062ms
maxEvenDividing2 tulemus: 8190 kestus 77.0044ms
maxEvenConjunction tulemus: 8190 kestus 111.0063ms
maxEvenConjunction2 tulemus: 8190 kestus 77.0044ms
max künnis: 16384
maxEvenDividing tulemus: 16382 kestus 109.0063ms
maxEvenDividing2 tulemus: 16382 kestus 77.0044ms
maxEvenConjunction tulemus: 16382 kestus 108.0062ms
maxEvenConjunction2 tulemus: 16382 kestus 77.0044ms
max piir: 32768
maxEvenDividing tulemus: 32766 kestus 112.0064ms
maxEvenDividing2 tulemus: 32766 kestus 77.0044ms
maxEvenConjunction tulemus: 32766 kestus 109.0062ms
maxEvenConjunction2 tulemus: 32766 kestus 78.0045ms
max piir: 65536
maxEvenDividing tulemus: 65534 kestus 109.0062ms
maxEvenDividing2 tulemus: 65534 kestus 75.0043ms
maxEvenConjunction tulemus: 65534 kestus 109.0063ms
maxEvenConjunction2 tulemus: 65534 kestus 79.0045ms
max piir: 131072
maxEvenDividing tulemus: 131070 kestus 108.0061ms
maxEvenDividing2 tulemus: 131070 kestus 76.0044ms
maxEvenConjunction tulemus: 131070 kestus 110.0063ms
maxEvenConjunction2 tulemus: 131070 kestus 80.0046ms
max piir: 262144
maxEvenDividing tulemus: 262142 kestus 110.0063ms
maxEvenDividing2 tulemus: 262142 kestus 76.0044ms
maxEvenConjunction tulemus: 262142 kestus 107.0061ms
maxEvenConjunction2 tulemus: 262142 kestus 78.0044ms
max piir: 524288
maxEvenDividing tulemus: 524286 kestus 109.0062ms
maxEvenDividing2 tulemus: 524286 kestus 78.0045ms
maxEvenConjunction tulemus: 524286 kestus 109.0062ms
maxEvenConjunction2 tulemus: 524286 kestus 80.0046ms
max piir: 1048576
maxEvenDividing tulemus: 1048574 kestus 109.0063ms
maxEvenDividing2 tulemus: 1048574 kestus 80.0045ms
maxEvenConjunction tulemus: 1048574 kestus 114.0066ms
maxEvenConjunction2 tulemus: 1048574 kestus 78.0044ms
max piir: 2097152
maxEvenDividing tulemus: 2097150 kestus 111.0064ms
maxEvenDividing2 tulemus: 2097150 kestus 79.0045ms
maxEvenConjunction tulemus: 2097150 kestus 112.0064ms
maxEvenConjunction2 tulemus: 2097150 kestus 77.0044ms
max piir: 4194304
maxEvenDividing tulemus: 4194302 kestus 111.0063ms
maxEvenDividing2 tulemus: 4194302 kestus 78.0045ms
maxEvenConjunction tulemus: 4194302 kestus 111.0063ms
maxEvenConjunction2 tulemus: 4194302 kestus 77.0044ms
max künnis: 8388608
maxEvenDividing tulemus: 8388606 kestus 109.0062ms
maxEvenDividing2 tulemus: 8388606 kestus 78.0045ms
maxEvenConjunction tulemus: 8388606 kestus 114.0065ms
maxEvenConjunction2 tulemus: 8388606 kestus 78.0045ms
max künnis: 16777216
maxEvenDividing tulemus: 16777214 kestus 109.0062ms
maxEvenDividing2 tulemus: 16777214 kestus 77.0044ms
maxEvenConjunction tulemus: 16777214 kestus 109.0063ms
maxEvenConjunction2 tulemus: 16777214 kestus 77.0044ms
max künnis: 33554432
maxEvenDividing tulemus: 33554430 kestus 113.0065ms
maxEvenDividing2 tulemus: 33554430 kestus 78.0045ms
maxEvenConjunction tulemus: 33554430 kestus 110.0063ms
maxEvenConjunction2 tulemus: 33554430 kestus 80.0045ms
max künnis: 67108864
maxEvenDividing tulemus: 67108860 kestus 112.0064ms
maxEvenDividing2 tulemus: 67108860 kestus 77.0044ms
maxEvenConjunction tulemus: 67108860 kestus 112.0064ms
maxEvenConjunction2 tulemus: 67108860 kestus 80.0046ms
max künnis: 134217728
maxEvenDividing tulemus: 134217726 kestus 109.0063ms
maxEvenDividing2 tulemus: 134217726 kestus 78.0044ms
maxEvenConjunction tulemus: 134217726 kestus 114.0065ms
maxEvenConjunction2 tulemus: 134217726 kestus 81.0047ms
max künnis: 268435456
maxEvenDividing tulemus: 268435446 kestus 111.0064ms
maxEvenDividing2 tulemus: 268435446 kestus 79.0045ms
maxEvenConjunction tulemus: 268435446 kestus 114.0065ms
maxEvenConjunction2 tulemus: 268435446 kestus 79.0045ms
max piir: 536870912
maxEvenDividing tulemus: 536870910 kestus 107.0062ms
maxEvenDividing2 tulemus: 536870910 kestus 76.0043ms
maxEvenConjunction tulemus: 536870910 kestus 109.0062ms
maxEvenConjunction2 tulemus: 536870910 kestus 80.0046ms
Ma ei leidnud arusaadavat selgitust, miks Go kompilaator ei optimeeri koodi ja kontrollib alati teist tingimust, isegi kui esimene on vale. Võib-olla on mu silmad lihtsalt "harjunud" ja ma ei näe mingit ilmset viga? Või peab kompilaatorile andma mingeid erilisemaid juhiseid? Oleksin tänulik selgete kommentaaride eest.
PS: Jah, huvi pärast jooksin sarnased testid Java 5 ja Java 7/8 — kõik oli korralik, käitusaeg ühesugune.
Allikas: habr.com
