Pointers 清除截断指针的更快或更慢的方法?
在我最近阅读的Pointers 清除截断指针的更快或更慢的方法?,pointers,go,slice,benchmarking,memset,Pointers,Go,Slice,Benchmarking,Memset,在我最近阅读的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, nilI
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
我设置了一个简单的循环方式,似乎for
循环方式更快
我想知道批量使用
copy
清除有什么好处。正如@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):]
}
}
}
还要注意的是,您的“批量”版本还多次将切片头分配给
nums
。有一种更快的方法来填充切片:您不需要额外的“nils”切片,只需开始填充切片,就可以将已填充的部分复制到未填充的部分。这也不需要更改/重新分配到nums
切片头。请参见我认为基准测试的结果正好相反。基于拷贝的清除比按循环清除快。nil
by循环可以利用运行时。在某些平台上,例如amd64
,这是memclr
的专业化,很难被打败。注意,对于值类型,它使用运行时.memclrNoHeapPointers
(例如[]int
)。因此,如果我们想将设置为nil
s,没有什么比编译器优化的for
循环更好的了,对吗?@satoru目前看来是这样的。您仍然可以尝试答案中提供的解决方案。谢谢。我已经尝试了字节中使用的算法。重复一下,速度大约是你答案中的两倍。我已经确认,当赋值为a[I]=nil
(如果它是值nil
的变量,则不起作用)时,使用优化的for
循环会更快。
BenchmarkSetNilOneByOne-4 96571 10626 ns/op
BenchmarkSetNilInBulk-4 266690 4023 ns/op