O que você acha, esses dois tipos de verificação de condições dentro do loop têm performance equivalente?
if a > b && c*2 > d {
....
}
// e
if a d {
....
}
Tudo comeƧou com um "exercĆcio para o cĆ©rebro", era necessĆ”rio dar um exemplo de busca ótima em um array de nĆŗmeros inteiros [-xā¦.x] para o maior nĆŗmero par. Fiquei curioso para saber o quanto a performance seria maior se usĆ”ssemos a multiplicação lógica por 1 para determinar se Ć© um nĆŗmero par ou nĆ£o.
//Ń ŃŠµŃнŃŃ
ŃŠøŃел ŠæŠ¾ŃŠ»ŠµŠ“ний Š±ŠøŃ Š²ŃŠµŠ³Š“а ŃŠ°Š²ŠµŠ½ 0
value & 1 == 0
//vs клаŃŃŠøŃŠµŃŠŗŠøŠ¹ Š¼ŠµŃŠ¾Š“
value % 2 == 0
Minha experiência em programação com Go não é muito grande, pouco mais de um ano e meio. Embora eu o tenha usado com frequência, foi principalmente para propósitos utilitÔrios (talvez exceto por um projeto relacionado a um serviço http de alta carga). Por isso, iniciei exatamente por ele. Abrimos o GoLand e escrevemos um teste simples.
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("capacidade inicial do array: " + fmt.Sprint(size))
var maxValue int32
// Vamos variar o intervalo de nĆŗmeros do mĆnimo
// ao mƔximo. Quanto menor o intervalo, mais
// tempo do processador serÔ gasto na operação
// de comparação do número atual com o jÔ encontrado e vice-versa.
for maxValue = 128; maxValue Obtemos um resultado que mostra que quanto maior o threshold, mais frequentes são as flutuações em termos de performance.
Comparelimite mƔximo: 128
resultado maxEvenDividing: 126 duração 116.0067ms
resultado maxEvenConjunction: 126 duração 116.0066ms
limite mƔximo: 16384
maxEvenDividing resultado: 16382 duração 115.0066ms
maxEvenConjunction resultado: 16382 duração 111.0064ms
......
limite mƔximo: 8388608
maxEvenDividing resultado: 8388606 duração 109.0063ms
resultado do maxEvenConjunction: 8388606 duração 109.0062ms
limite mƔximo: 16777216
resultado do maxEvenDividing: 16777214 duração 108.0062ms
resultado do maxEvenConjunction: 16777214 duração 109.0062ms
limite mƔximo: 33554432
resultado do maxEvenDividing: 33554430 duração 114.0066ms
resultado do maxEvenConjunction: 33554430 duração 110.0063ms
limite mƔximo: 67108864
resultado do maxEvenDividing: 67108860 duração 111.0064ms
resultado do maxEvenConjunction: 67108860 duração 109.0062ms
limite mƔximo: 134217728
resultado do maxEvenDividing: 134217726 duração 108.0062ms
resultado do maxEvenConjunction: 134217726 duração 109.0063ms
limite mƔximo: 268435456
resultado do maxEvenDividing: 268435446 duração 111.0063ms
resultado do maxEvenConjunction: 268435446 duração 110.0063ms
Ć claro que, nesse caso, para diferentes limites mĆ”ximos temos diferentes conjuntos de dados para teste, a carga do processador (no meu notebook i5-2540M) varia em torno de 20 a 30%, e a memória consumida pelo aplicativo rodando no GoLand Ć© de aproximadamente 813MB ā isso tambĆ©m afeta a precisĆ£o do resultado, Ć© necessĆ”rio implementar o salvamento dos conjuntos de teste no disco e executar todos os testes para cada limite isoladamente.
E ao refletir sobre como implementar tudo isso com o mĆnimo de custos, corrigi automaticamente a verificação da condição.
if value > current && value&1 == 0 {
current = value
}
para
if value <= current {
continue;
}
if value&1 == 0 {
current = value
}
rodo os testes novamente... e nĆ£o consigo entender nada š
O tempo gasto para a execução começa a diferir não em porcentagens ou frações de porcentagem, mas em 10 a 15%. Escrevo rapidamente mais 2 testes:
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
}
rodo e recebo esta imagem:capacidade inicial do array: 100000000
limite mƔximo: 128
resultado do maxEvenDividing: 126 duração 116.0066ms
resultado do maxEvenDividing2: 126 duração 79.0045ms
resultado do maxEvenConjunction: 126 duração 114.0065ms
resultado do maxEvenConjunction2: 126 duração 83.0048ms
limite mƔximo: 256
resultado do maxEvenDividing: 254 duração 111.0063ms
resultado do maxEvenDividing2: 254 duração 77.0044ms
resultado do maxEvenConjunction: 254 duração 110.0063ms
resultado do maxEvenConjunction2: 254 duração 80.0046ms
limite mƔximo: 512
resultado do maxEvenDividing: 510 duração 114.0066ms
resultado do maxEvenDividing2: 510 duração 80.0045ms
resultado do maxEvenConjunction: 510 duração 110.0063ms
resultado do maxEvenConjunction2: 510 duração 80.0046ms
limite mƔximo: 1024
resultado do maxEvenDividing: 1022 duração 109.0063ms
resultado do maxEvenDividing2: 1022 duração 77.0044ms
resultado do maxEvenConjunction: 1022 duração 111.0063ms
resultado do maxEvenConjunction2: 1022 duração 81.0047ms
limite mƔximo: 2048
resultado do maxEvenDividing: 2046 duração 114.0065ms
resultado do maxEvenDividing2: 2046 duração 79.0045ms
resultado do maxEvenConjunction: 2046 duração 113.0065ms
maxEvenConjunction2 resultado: 2046 duração 81.0046ms
limite mƔximo: 4096
maxEvenDividing resultado: 4094 duração 114.0065ms
maxEvenDividing2 resultado: 4094 duração 80.0046ms
maxEvenConjunction resultado: 4094 duração 111.0063ms
maxEvenConjunction2 resultado: 4094 duração 78.0045ms
limite mƔximo: 8192
maxEvenDividing resultado: 8190 duração 107.0062ms
maxEvenDividing2 resultado: 8190 duração 77.0044ms
maxEvenConjunction resultado: 8190 duração 111.0063ms
maxEvenConjunction2 resultado: 8190 duração 77.0044ms
limite mƔximo: 16384
maxEvenDividing resultado: 16382 duração 109.0063ms
maxEvenDividing2 resultado: 16382 duração 77.0044ms
maxEvenConjunction resultado: 16382 duração 108.0062ms
maxEvenConjunction2 resultado: 16382 duração 77.0044ms
limite mƔximo: 32768
maxEvenDividing resultado: 32766 duração 112.0064ms
maxEvenDividing2 resultado: 32766 duração 77.0044ms
maxEvenConjunction resultado: 32766 duração 109.0062ms
maxEvenConjunction2 resultado: 32766 duração 78.0045ms
limite mƔximo: 65536
maxEvenDividing resultado: 65534 duração 109.0062ms
maxEvenDividing2 resultado: 65534 duração 75.0043ms
maxEvenConjunction resultado: 65534 duração 109.0063ms
maxEvenConjunction2 resultado: 65534 duração 79.0045ms
limite mƔximo: 131072
maxEvenDividing resultado: 131070 duração 108.0061ms
maxEvenDividing2 resultado: 131070 duração 76.0044ms
maxEvenConjunction resultado: 131070 duração 110.0063ms
maxEvenConjunction2 resultado: 131070 duração 80.0046ms
limite mƔximo: 262144
maxEvenDividing resultado: 262142 duração 110.0063ms
maxEvenDividing2 resultado: 262142 duração 76.0044ms
maxEvenConjunction resultado: 262142 duração 107.0061ms
maxEvenConjunction2 resultado: 262142 duração 78.0044ms
limite mƔximo: 524288
maxEvenDividing resultado: 524286 duração 109.0062ms
maxEvenDividing2 resultado: 524286 duração 78.0045ms
maxEvenConjunction resultado: 524286 duração 109.0062ms
maxEvenConjunction2 resultado: 524286 duração 80.0046ms
limite mƔximo: 1048576
maxEvenDividing resultado: 1048574 duração 109.0063ms
maxEvenDividing2 resultado: 1048574 duração 80.0045ms
maxEvenConjunction resultado: 1048574 duração 114.0066ms
maxEvenConjunction2 resultado: 1048574 duração 78.0044ms
limite mƔximo: 2097152
maxEvenDividing resultado: 2097150 duração 111.0064ms
maxEvenDividing2 resultado: 2097150 duração 79.0045ms
maxEvenConjunction resultado: 2097150 duração 112.0064ms
maxEvenConjunction2 resultado: 2097150 duração 77.0044ms
limite mƔximo: 4194304
maxEvenDividing resultado: 4194302 duração 111.0063ms
maxEvenDividing2 resultado: 4194302 duração 78.0045ms
maxEvenConjunction resultado: 4194302 duração 111.0063ms
maxEvenConjunction2 resultado: 4194302 duração 77.0044ms
limite mƔximo: 8388608
maxEvenDividing resultado: 8388606 duração 109.0062ms
maxEvenDividing2 resultado: 8388606 duração 78.0045ms
maxEvenConjunction resultado: 8388606 duração 114.0065ms
maxEvenConjunction2 resultado: 8388606 duração 78.0045ms
limite mƔximo: 16777216
maxEvenDividing resultado: 16777214 duração 109.0062ms
maxEvenDividing2 resultado: 16777214 duração 77.0044ms
maxEvenConjunction resultado: 16777214 duração 109.0063ms
maxEvenConjunction2 resultado: 16777214 duração 77.0044ms
limite mƔximo: 33554432
maxEvenDividing resultado: 33554430 duração 113.0065ms
maxEvenDividing2 resultado: 33554430 duração 78.0045ms
resultado do maxEvenConjunction: 33554430 duração 110.0063ms
maxEvenConjunction2 resultado: 33554430 duração 80.0045ms
limite mƔximo: 67108864
maxEvenDividing resultado: 67108860 duração 112.0064ms
maxEvenDividing2 resultado: 67108860 duração 77.0044ms
maxEvenConjunction resultado: 67108860 duração 112.0064ms
maxEvenConjunction2 resultado: 67108860 duração 80.0046ms
limite mƔximo: 134217728
maxEvenDividing resultado: 134217726 duração 109.0063ms
maxEvenDividing2 resultado: 134217726 duração 78.0044ms
maxEvenConjunction resultado: 134217726 duração 114.0065ms
maxEvenConjunction2 resultado: 134217726 duração 81.0047ms
limite mƔximo: 268435456
maxEvenDividing resultado: 268435446 duração 111.0064ms
maxEvenDividing2 resultado: 268435446 duração 79.0045ms
maxEvenConjunction resultado: 268435446 duração 114.0065ms
maxEvenConjunction2 resultado: 268435446 duração 79.0045ms
limite mƔximo: 536870912
maxEvenDividing resultado: 536870910 duração 107.0062ms
maxEvenDividing2 resultado: 536870910 duração 76.0043ms
maxEvenConjunction resultado: 536870910 duração 109.0062ms
maxEvenConjunction2 resultado: 536870910 duração 80.0046ms
NĆ£o encontrei uma explicação clara do porquĆŖ o compilador Go nĆ£o otimiza o código e sempre verifica a segunda condição, mesmo que a primeira seja falsa ā talvez eu simplesmente nĆ£o esteja vendo algum erro óbvio? Ou preciso indicar algumas instruƧƵes especiais para o compilador? Ficaria feliz com comentĆ”rios esclarecedores.
PS: Sim, por curiosidade, executei testes semelhantes em Java 5 e Java 7/8 ā tudo claro, o tempo de execução Ć© igual.
Fonte: habr.com
