在我最近读到的一个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有什么好处。
发布于 2020-05-18 21:04:00
正如@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?
https://stackoverflow.com/questions/61869098
复制相似问题