Why is creating a variable size Slice slower?

Asked

Viewed 86 times

4

Using the make([]byte, tamanho) he has a different behavior when the tamanho is a variable or a constant.

Consider the two codes:

package Testes

import (
    "testing"
)

func BenchmarkConstante(b *testing.B) {
    const tamanho = 1024
    for n := 0; n < b.N; n++ {
        _ = make([]byte, tamanho)
    }
}
func BenchmarkVariavel(b *testing.B) {
    var tamanho = 1024
    for n := 0; n < b.N; n++ {
        _ = make([]byte, tamanho)
    }
}

The only difference between the two is const and var.

They return:

50000000            35.5 ns/op
10000000           181 ns/op

Both have the same tamanho, of 1024. The only difference is that the first is constant (it also has the same effect if using make([]byte, 1024) directly), but the second case is slower than the first.

Using the first shape can be five times faster than using a variable. Now, why is this? Because using a variable value can have a difference so great?

I believe they’re both fast enough, but what’s strange is there’s such a difference to something so simple.


My guess is that the compiler can reduce something when using a constant value. Meanwhile, using a variable would add some other checks, for example checks if the value is less than zero, it does not need to use a constant value, since this is done at the time it compiles.

I think it might be something like this, but what exactly would it be?

1 answer

2


In golang when you create a constant it is a literal, a scalar value that may or may not be named. In other words, its value or expression is directly defined at compile time as if we had written directly into the code. Let’s look at two cases:

In the first, we write a constant and then two variables and then their concatenation. In the second case, we change only v1 to be a constant. The result in both cases is Hello, Ari, however the behavior in the compilation is different.

//primeiro caso
func main() {
    const v0 = "Hello, "
    var v1 = "Ari"
    var v2 = v0 + v1
    println(v2)
}

//segundo caso
func main() {
    const v0 = "Hello, "
    const v1 = "Ari"
    var v2 = v0 + v1
    println(v2)
}

In the first case there is an allocation of v1 for the heap and this causes the concatenation operation to fetch the value and then concatenate. Behold:

inserir a descrição da imagem aqui

In the second case it is the same thing as writing literally ```v2 = "Hello, Ari", see:

inserir a descrição da imagem aqui

Thus, the cost of getting the value and then operating on it is more costly than keeping the value directly in the compiled code. This is quite obvious! Technically, it can be said that const work at compilation time and var work in time of Runtime.

That being said, we can easily understand that if we consume the heap with that constant, the cost of keeping it there is no longer worth it when compared to a variable. That is, if you literally gradually increase your Slice size you will see that there will come a time when both constants and variables have the same cost. So if you use, for example, [const|var] tamanho = 64 * 1024 the result will be as follows (the first is 16*1024 and the second is 64*1024):

inserir a descrição da imagem aqui

P.S.: the difference in the second case is insignificant, given several executions.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.