dongpang2029
2019-08-07 09:32
浏览 203
已采纳

如何在不将所有值归零的情况下初始化长Golang数组?

When creating an array in Go, it seems the array will always be zeroed, even if different values will be set right after the initialization, for example when the value should be set to the index in the array.

One way to avoid this is to use array literals, such as a = [5]int{0,1,2,3,4}, but it becomes impractical for long arrays. I'm wondering what is the best way to perform the initialization.

Surprisingly, the named return function outperforms the composite literal initialization for large arrays.

I've created the following benchmark to compare the performance:

package main

import "testing"

const N = 1000000

var result [N]int

func arrayLiteral() [N]int {
    // Replace the 3 dots with the actual value
    // I copy-pasted the output of an other program to do this
    return [N]int{0,1,2,3,...,N-1}
}

func arrayLoopNamedReturn() (a [N]int) {
    for i := 0; i < N; i++ {
        a[i] = i
    }
    return
}

func arrayLoop() [N]int {
    var a [N]int
    for i := 0; i < N; i++ {
        a[i] = i
    }
    return a
}

func BenchmarkArrayLoop(b *testing.B) {
    var r [N]int
    for n := 0; n < b.N; n++ {
        r = arrayLoop()
    }
    result = r
}

func BenchmarkArrayLoopNamedReturn(b *testing.B) {
    var r [N]int
    for n := 0; n < b.N; n++ {
        r = arrayLoopNamedReturn()
    }
    result = r
}

func BenchmarkArrayLiteral(b *testing.B) {
    var r [N]int
    for n := 0; n < b.N; n++ {
        r = arrayLiteral()
    }
    result = r
}

Results:

N = 10,000
BenchmarkArrayLoop-8                      200000              9041 ns/op
BenchmarkArrayLoopNamedReturn-8           200000              6327 ns/op
BenchmarkArrayLiteral-8                   300000              4300 ns/op

N = 100,000
BenchmarkArrayLoop-8                       10000            191582 ns/op
BenchmarkArrayLoopNamedReturn-8            20000             76125 ns/op
BenchmarkArrayLiteral-8                    20000             62714 ns/op

N = 1,000,000
BenchmarkArrayLoop-8                         500           2635713 ns/op
BenchmarkArrayLoopNamedReturn-8             1000           1537282 ns/op
BenchmarkArrayLiteral-8                     1000           1854348 ns/op

Observations:

  1. I did not expect that naming the return value would make a difference for the loop, I thought surely the compiler would do some optimization. For 1,000,000, it becomes faster than the literal initialization.

  2. I expected a linear scaling, I do not understand why it is not the case, for either of the methods.

I'm not sure how to explain this, even though it seems to be extremely basic. Any ideas ?

Edit: There is an open issue on Github complaining that naming the return value should not make a difference. I also found this to be a surprising behavior.

  • 写回答
  • 好问题 提建议
  • 追加酬金
  • 关注问题
  • 邀请回答

2条回答 默认 最新

相关推荐 更多相似问题