【问题标题】:A faster or slower way to clear truncated pointers?清除截断指针的更快或更慢的方法?
【发布时间】:2020-09-04 05:20:08
【问题描述】:

在我最近阅读的一个truncate实现中,作者使用以下方式清除截断项:

var nilItems    = make(items, 16)

func (s *items) truncate(index int) {
    var toClear items
    *s, toClear = (*s)[:index], (*s)[index:]
    for len(toClear) > 0 {
        toClear = toClear[copy(toClear, nilItems):]
    }
}

当我需要清除不需要的项目时,我只需遍历切片并将项目一一设置为nil

我设置了一个简单的benchmark,看来for的循环方式更快。

我想知道使用copy 批量清算有什么好处。

【问题讨论】:

  • 我看到基准测试显示相反。 Copy based clear 比 nil by loop 快。
  • nil by 循环可以在某些平台上使用runtime.memclrHasPointers,例如amd64 这是一个 memclr 专业化,并且很难被击败。注意它使用runtime.memclrNoHeapPointers 的值类型(例如[]int)。

标签: pointers go slice benchmarking memset


【解决方案1】:

正如@MartinGallagher 所提到的,您的循环已被编译器识别和优化,而copy() 版本“做了太多事情”并且没有进行优化。

如果您更改示例以填充非nil 指针值,您将看到循环版本落后。也不要在基准循环内部分配 (make()),在外部执行,并使用 b.ResetTimer() 排除该时间。

你也有一个非常小的切片,如果你增加它的大小,差异会更明显:

var x = new(int)

func BenchmarkSetNilOneByOne(b *testing.B) {
    nums := make([]*int, 12800)
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        for i := range nums {
            nums[i] = x
        }
    }
}

func BenchmarkSetNilInBulk(b *testing.B) {
    nils := make([]*int, 128)
    for i := range nils {
        nils[i] = x
    }

    orig := make([]*int, 12800)
    var nums []*int
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        nums = orig
        for len(nums) > 0 {
            nums = nums[copy(nums, nils):]
        }
    }
}

基准测试结果:

BenchmarkSetNilOneByOne-4          96571         10626 ns/op
BenchmarkSetNilInBulk-4           266690          4023 ns/op

另请注意,您的“批量”版本还会多次将切片标题分配给nums。有一种更快的填充切片的方法:您不需要额外的“nils”切片,只需开始填充切片,您可以将已填充的部分复制到未填充的部分。这也不需要更改/重新分配给nums 切片标头。见Is there analog of memset in go?

【讨论】:

  • 所以如果我们想设置nils,没有什么比编译器优化的for循环更好了,对吧?
  • @satoru 目前看来是这样。您仍然可以尝试Is there analog of memset in go? 答案中提供的解决方案。
  • 谢谢。我已经尝试过bytes.Repeat 中使用的算法,它的速度大约快两倍,如您的答案所示。而且我已经确认,当赋值为a[i] = nil 时使用优化的for 循环会更快(如果它是值nil 的变量,则它不起作用)。
猜你喜欢
  • 2013-09-20
  • 2019-06-29
  • 2021-07-21
  • 2012-12-22
  • 2021-03-02
  • 2011-01-02
  • 1970-01-01
  • 1970-01-01
  • 2013-05-01
相关资源
最近更新 更多