dpsq8476 2015-06-15 21:24
浏览 192
已采纳

Go slice调整大小时的不同性能

I'm spending some time experimenting with Go's internals and I ended up writing my own implementation of a stack using slices. As correctly pointed out by a reddit user in this post and as outlined by another user in this SO answer Go already tries to optimise slices resize.

Turns out, though, that I rather have performance gains using my own implementation of slice growing rather than sticking with the default one.

This is the structure I use for holding the stack:

type Stack struct {
    slice []interface{}
    blockSize int
}

const s_DefaultAllocBlockSize = 20;

This is my own implementation of the Push method

func (s *Stack) Push(elem interface{}) {
    if len(s.slice) + 1 == cap(s.slice) {
        slice := make([]interface{}, 0, len(s.slice) + s.blockSize)
        copy(slice, s.slice)
        s.slice = slice
    }

    s.slice = append(s.slice, elem)
}

This is a plain implementation

func (s *Stack) Push(elem interface{}) {
    s.slice = append(s.slice, elem)
}

Running the benchmarks I've implemented using Go's testing package my own implementation performs this way:

Benchmark_PushDefaultStack  20000000            87.7 ns/op        24 B/op          1 allocs/op

While relying on the plain append the results are the following

Benchmark_PushDefaultStack  10000000           209 ns/op          90 B/op          1 allocs/op

The machine I run tests on is an early 2011 Mac Book Pro, 2.3 GHz Intel Core i5 with 8GB of RAM 1333MHz DDR3

EDIT The actual question is: is my implementation really faster than the default append behavior? Or am I not taking something into account?

  • 写回答

2条回答 默认 最新

  • duanhuancong1969 2015-06-16 08:51
    关注

    Reading your code, tests, benchmarks, and results it's easy to see that they are flawed. A full code review is beyond the scope of StackOverflow.

    One specific bug.

    // Push pushes a new element to the stack
    func (s *Stack) Push(elem interface{}) {
        if len(s.slice)+1 == cap(s.slice) {
            slice := make([]interface{}, 0, len(s.slice)+s.blockSize)
            copy(slice, s.slice)
            s.slice = slice
        }
    
        s.slice = append(s.slice, elem)
    }
    

    Should be

    // Push pushes a new element to the stack
    func (s *Stack) Push(elem interface{}) {
        if len(s.slice)+1 == cap(s.slice) {
            slice := make([]interface{}, len(s.slice), len(s.slice)+s.blockSize)
            copy(slice, s.slice)
            s.slice = slice
        }
    
        s.slice = append(s.slice, elem)
    }
    

    copying slices

    The function copy copies slice elements from a source src to a destination dst and returns the number of elements copied. The number of elements copied is the minimum of len(src) and len(dst).

    You copied 0, you should have copied len(s.slice).

    As expected, your Push algorithm is inordinately slow:

    append:
    
    Benchmark_PushDefaultStack-4     2000000           941 ns/op          49 B/op          1 allocs/op
    
    alediaferia:
    
    Benchmark_PushDefaultStack-4      100000       1246315 ns/op       42355 B/op          1 allocs/op
    

    This how append works: append complexity.

    There are other things wrong too. Your benchmark results are often not valid.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 mars2d在vue3中的引入问题
  • ¥50 h5唤醒支付宝并跳转至向小荷包转账界面
  • ¥15 算法题:数的划分,用记忆化DFS做WA求调
  • ¥15 chatglm-6b应用到django项目中,模型加载失败
  • ¥15 CreateBitmapFromWicBitmap内存释放问题。
  • ¥30 win c++ socket
  • ¥15 C# datagridview 栏位进度
  • ¥15 vue3页面el-table页面数据过多
  • ¥100 vue3中融入gRPC-web
  • ¥15 kali环境运行volatility分析android内存文件,缺profile