A mendoni, a janë ekuivalente këto dy metoda të kontrollit të kushteve brenda ciklit në performancë?
if a > b && c*2 > d {
....
}
// dhe
if a d {
....
}
E gjithçka filloi me "ngrohje për trurin", duhej të jepja një shembull të kërkimit optimal në një masiv numrash të gjithëmbarësh [-x….x] për numrin më të madh çift. Më interesonte sa ishte më e lartë performanca nëse për të përcaktuar nëse një numër është çift, do të përdorej shumëzimi logjik me 1.
//у четных чисел последний бит всегда равен 0
value & 1 == 0
//vs классический метод
value % 2 == 0
Eksperienca ime në programimin me Go nuk është shumë e madhe, pak më shumë se një vit e gjysmë, e kam përdorur shpesh, por kryesisht për qëllime utilitare (ndoshta përveç një projekti të lidhur me një shërbim http me ngarkesë të lartë), prandaj e fillova pikërisht me të. Hapim GoLand dhe shkruajmë një test të thjeshtë.
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("kapaciteti fillestar i masivit: " + fmt.Sprint(size))
var maxValue int32
// Do të variablim gamën e numrave nga minimalja
// deri në maksimale. Sa më i vogël gamën, aq më shumë
// koha e përpunimit do të shkojë në operacionin
// për krahasimin e numrit aktual me numrin e gjetur më parë
for maxValue = 128; maxValue Marrim rezultatin, në të cilin duket se sa më i lartë të jetë pragu, aq më shpesh shfaqen fluktuacione në performancë.
Krahasonipragu maksimal: 128
rezultati maxEvenDividing: 126 kohë 116.0067ms
rezultati maxEvenConjunction: 126 kohë 116.0066ms
pragu maksimal: 16384
rezultati maxEvenDividing: 16382 koha 115.0066ms
rezultati maxEvenConjunction: 16382 koha 111.0064ms
......
pragu maksimal: 8388608
rezultati maxEvenDividing: 8388606 koha 109.0063ms
rezultati maxEvenConjunction: 8388606 kohëzgjatja 109.0062ms
pragu maksimal: 16777216
rezultati maxEvenDividing: 16777214 kohëzgjatja 108.0062ms
rezultati maxEvenConjunction: 16777214 kohëzgjatja 109.0062ms
pragu maksimal: 33554432
rezultati maxEvenDividing: 33554430 kohëzgjatja 114.0066ms
rezultati maxEvenConjunction: 33554430 kohëzgjatja 110.0063ms
pragu maksimal: 67108864
rezultati maxEvenDividing: 67108860 kohëzgjatja 111.0064ms
rezultati maxEvenConjunction: 67108860 kohëzgjatja 109.0062ms
pragu maksimal: 134217728
rezultati maxEvenDividing: 134217726 kohëzgjatja 108.0062ms
rezultati maxEvenConjunction: 134217726 kohëzgjatja 109.0063ms
pragu maksimal: 268435456
rezultati maxEvenDividing: 268435446 kohëzgjatja 111.0063ms
rezultati maxEvenConjunction: 268435446 kohëzgjatja 110.0063ms
Është e qartë se në këtë rast, për pragje të ndryshme kemi grupe të ndryshme të të dhënave testuese, ngarkesa e procesorit (në laptopin tim i5-2540M) varion rreth 20..30%, memoria e zënë nga aplikacioni të cilin e kam ekzekutuar nga GoLand është rreth 813Mb — kjo gjithashtu ndikon në besueshmërinë e rezultatit, duhet të realizoj ruajtjen e grupeve të testit në disk dhe të ekzekutoj të gjitha testet për çdo prag të izoluar nga njëri-tjetri.
Dhe, duke menduar se si të realizoj gjithë këtë me minimale shpenzime, automatikisht e korrigjoj kontrollin e kushteve
if value > current && value&1 == 0 {
current = value
}
në
if value <= current {
continue;
}
if value&1 == 0 {
current = value
}
ekzekutoj testet edhe një herë… dhe ndaloj së kuptuari gjithçka 🙂
Koha e harxhuar për ekzekutimin fillon të ndryshojë jo më në përqindje/pjesë të përqindjes, por në 10..15% Shpejt shkruaj edhe 2 teste të tjera:
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
}
ekzekutoj dhe marr një pamje të tillë:kapaciteti fillestar i array: 100000000
pragu maksimal: 128
rezultati maxEvenDividing: 126 kohëzgjatja 116.0066ms
rezultati maxEvenDividing2: 126 kohëzgjatja 79.0045ms
rezultati maxEvenConjunction: 126 kohëzgjatja 114.0065ms
rezultati maxEvenConjunction2: 126 kohëzgjatja 83.0048ms
pragu maksimal: 256
rezultati maxEvenDividing: 254 kohëzgjatja 111.0063ms
rezultati maxEvenDividing2: 254 kohëzgjatja 77.0044ms
rezultati maxEvenConjunction: 254 kohëzgjatja 110.0063ms
rezultati maxEvenConjunction2: 254 kohëzgjatja 80.0046ms
pragu maksimal: 512
rezultati maxEvenDividing: 510 kohëzgjatja 114.0066ms
rezultati maxEvenDividing2: 510 kohëzgjatja 80.0045ms
rezultati maxEvenConjunction: 510 kohëzgjatja 110.0063ms
rezultati maxEvenConjunction2: 510 kohëzgjatja 80.0046ms
pragu maksimal: 1024
rezultati maxEvenDividing: 1022 kohëzgjatja 109.0063ms
rezultati maxEvenDividing2: 1022 kohëzgjatja 77.0044ms
rezultati maxEvenConjunction: 1022 kohëzgjatja 111.0063ms
rezultati maxEvenConjunction2: 1022 kohëzgjatja 81.0047ms
pragu maksimal: 2048
rezultati maxEvenDividing: 2046 kohëzgjatja 114.0065ms
rezultati maxEvenDividing2: 2046 kohëzgjatja 79.0045ms
rezultati maxEvenConjunction: 2046 kohëzgjatja 113.0065ms
maxEvenConjunction2 rezultati: 2046 kohëzgjatja 81.0046ms
pragu maksimal: 4096
maxEvenDividing rezultati: 4094 kohëzgjatja 114.0065ms
maxEvenDividing2 rezultati: 4094 kohëzgjatja 80.0046ms
maxEvenConjunction rezultati: 4094 kohëzgjatja 111.0063ms
maxEvenConjunction2 rezultati: 4094 kohëzgjatja 78.0045ms
pragu maksimal: 8192
maxEvenDividing rezultati: 8190 kohëzgjatja 107.0062ms
maxEvenDividing2 rezultati: 8190 kohëzgjatja 77.0044ms
maxEvenConjunction rezultati: 8190 kohëzgjatja 111.0063ms
maxEvenConjunction2 rezultati: 8190 kohëzgjatja 77.0044ms
pragu maksimal: 16384
maxEvenDividing rezultati: 16382 kohëzgjatja 109.0063ms
maxEvenDividing2 rezultati: 16382 kohëzgjatja 77.0044ms
maxEvenConjunction rezultati: 16382 kohëzgjatja 108.0062ms
maxEvenConjunction2 rezultati: 16382 kohëzgjatja 77.0044ms
pragu maksimal: 32768
maxEvenDividing rezultati: 32766 kohëzgjatja 112.0064ms
maxEvenDividing2 rezultati: 32766 kohëzgjatja 77.0044ms
maxEvenConjunction rezultati: 32766 kohëzgjatja 109.0062ms
maxEvenConjunction2 rezultati: 32766 kohëzgjatja 78.0045ms
pragu maksimal: 65536
maxEvenDividing rezultati: 65534 kohëzgjatja 109.0062ms
maxEvenDividing2 rezultati: 65534 kohëzgjatja 75.0043ms
maxEvenConjunction rezultati: 65534 kohëzgjatja 109.0063ms
maxEvenConjunction2 rezultati: 65534 kohëzgjatja 79.0045ms
pragu maksimal: 131072
maxEvenDividing rezultati: 131070 kohëzgjatja 108.0061ms
maxEvenDividing2 rezultati: 131070 kohëzgjatja 76.0044ms
maxEvenConjunction rezultati: 131070 kohëzgjatja 110.0063ms
maxEvenConjunction2 rezultati: 131070 kohëzgjatja 80.0046ms
pragu maksimal: 262144
maxEvenDividing rezultati: 262142 kohëzgjatja 110.0063ms
maxEvenDividing2 rezultati: 262142 kohëzgjatja 76.0044ms
maxEvenConjunction rezultati: 262142 kohëzgjatja 107.0061ms
maxEvenConjunction2 rezultati: 262142 kohëzgjatja 78.0044ms
pragu maksimal: 524288
maxEvenDividing rezultati: 524286 kohëzgjatja 109.0062ms
maxEvenDividing2 rezultati: 524286 kohëzgjatja 78.0045ms
maxEvenConjunction rezultati: 524286 kohëzgjatja 109.0062ms
maxEvenConjunction2 rezultati: 524286 kohëzgjatja 80.0046ms
pragu maksimal: 1048576
maxEvenDividing rezultati: 1048574 kohëzgjatja 109.0063ms
maxEvenDividing2 rezultati: 1048574 kohëzgjatja 80.0045ms
maxEvenConjunction rezultati: 1048574 kohëzgjatja 114.0066ms
maxEvenConjunction2 rezultati: 1048574 kohëzgjatja 78.0044ms
pragu maksimal: 2097152
maxEvenDividing rezultati: 2097150 kohëzgjatja 111.0064ms
maxEvenDividing2 rezultati: 2097150 kohëzgjatja 79.0045ms
maxEvenConjunction rezultati: 2097150 kohëzgjatja 112.0064ms
maxEvenConjunction2 rezultati: 2097150 kohëzgjatja 77.0044ms
pragu maksimal: 4194304
maxEvenDividing rezultati: 4194302 kohëzgjatja 111.0063ms
maxEvenDividing2 rezultati: 4194302 kohëzgjatja 78.0045ms
maxEvenConjunction rezultati: 4194302 kohëzgjatja 111.0063ms
maxEvenConjunction2 rezultati: 4194302 kohëzgjatja 77.0044ms
pragu maksimal: 8388608
maxEvenDividing rezultati: 8388606 kohëzgjatja 109.0062ms
maxEvenDividing2 rezultati: 8388606 kohëzgjatja 78.0045ms
maxEvenConjunction rezultati: 8388606 kohëzgjatja 114.0065ms
maxEvenConjunction2 rezultati: 8388606 kohëzgjatja 78.0045ms
pragu maksimal: 16777216
maxEvenDividing rezultati: 16777214 kohëzgjatja 109.0062ms
maxEvenDividing2 rezultati: 16777214 kohëzgjatja 77.0044ms
maxEvenConjunction rezultati: 16777214 kohëzgjatja 109.0063ms
maxEvenConjunction2 rezultati: 16777214 kohëzgjatja 77.0044ms
pragu maksimal: 33554432
maxEvenDividing rezultati: 33554430 kohëzgjatja 113.0065ms
maxEvenDividing2 rezultati: 33554430 kohëzgjatja 78.0045ms
rezultati maxEvenConjunction: 33554430 kohëzgjatja 110.0063ms
maxEvenConjunction2 rezultati: 33554430 kohëzgjatja 80.0045ms
pragu maksimal: 67108864
maxEvenDividing rezultati: 67108860 kohëzgjatja 112.0064ms
maxEvenDividing2 rezultati: 67108860 kohëzgjatja 77.0044ms
maxEvenConjunction rezultati: 67108860 kohëzgjatja 112.0064ms
maxEvenConjunction2 rezultati: 67108860 kohëzgjatja 80.0046ms
pragu maksimal: 134217728
maxEvenDividing rezultati: 134217726 kohëzgjatja 109.0063ms
maxEvenDividing2 rezultati: 134217726 kohëzgjatja 78.0044ms
maxEvenConjunction rezultati: 134217726 kohëzgjatja 114.0065ms
maxEvenConjunction2 rezultati: 134217726 kohëzgjatja 81.0047ms
pragu maksimal: 268435456
maxEvenDividing rezultati: 268435446 kohëzgjatja 111.0064ms
maxEvenDividing2 rezultati: 268435446 kohëzgjatja 79.0045ms
maxEvenConjunction rezultati: 268435446 kohëzgjatja 114.0065ms
maxEvenConjunction2 rezultati: 268435446 kohëzgjatja 79.0045ms
pragu maksimal: 536870912
maxEvenDividing rezultati: 536870910 kohëzgjatja 107.0062ms
maxEvenDividing2 rezultati: 536870910 kohëzgjatja 76.0043ms
maxEvenConjunction rezultat: 536870910 kohëzgjatja 109.0062ms
maxEvenConjunction2 rezultat: 536870910 kohëzgjatja 80.0046ms
Nuk kam gjetur një shpjegim të qartë pse kompajleri Go nuk e optimizon kodin dhe gjithmonë kontrollon kushtin e dytë, edhe kur i pari është i gabuar — ndoshta ndaj kam humbur ndonjë detaj dhe nuk shoh një gabim të dukshëm? Apo duhet t'i jap disa udhëzime të veçanta kompajlerit? Do të isha i lumtur për komentet e ndihmës.
PS: Po, për të kaluar kohën, kam testuar teste të ngjashme në Java 5 dhe Java 7/8 — çdo gjë është e qartë, koha e ekzekutimit është e njëjtë.
Burimi: habr.com
