使用循环的最简单解决方案如下:
func memsetLoop(a []int, v int) {
for i := range a {
a[i] = v
}
}
标准库中没有支持memset
,但我们可以利用内置的copy()
函数进行高度优化。
使用多次copy()
我们可以手动设置第一个元素,并使用copy()
将已设置部分复制到未设置部分,其中已设置部分每次都会变得越来越大(翻倍),所以迭代次数为log(n)
:
func memsetRepeat(a []int, v int) {
if len(a) == 0 {
return
}
a[0] = v
for bp := 1; bp < len(a); bp *= 2 {
copy(a[bp:], a[:bp])
}
}
这个解决方案的灵感来自于bytes.Repeat()
的实现。如果您只想创建一个填充有相同值的新[]byte
,您可以使用bytes.Repeat()
函数。但对于现有的切片或除[]byte
以外的其他切片,您不能使用它,为此,您可以使用memsetRepeat()
。
对于小的切片,memsetRepeat()
可能比memsetLoop()
慢(但对于小的切片并不重要,它会在瞬间运行)。
由于使用了快速的copy()
,如果元素数量增加,memsetRepeat()
将会更快。
对这两种解决方案进行基准测试:
var a = make([]int, 1000)
func BenchmarkLoop(b *testing.B) {
for i := 0; i < b.N; i++ {
memsetLoop(a, 10)
}
}
func BenchmarkRepeat(b *testing.B) {
for i := 0; i < b.N; i++ {
memsetRepeat(a, 11)
}
}
基准测试结果
100个元素: 比原来快了约1.15倍
BenchmarkLoop 20000000 81.6 ns/op
BenchmarkRepeat 20000000 71.0 ns/op
1,000 个元素: 速度提升 ~2.5 倍
BenchmarkLoop 2000000 706 ns/op
BenchmarkRepeat 5000000 279 ns/op
1万个元素:快大约2倍
BenchmarkLoop 200000 7029 ns/op
BenchmarkRepeat 500000 3544 ns/op
100,000个元素:快大约1.5倍
BenchmarkLoop 20000 70671 ns/op
BenchmarkRepeat 30000 45213 ns/op
性能提升最高的范围在3800-4000个元素左右,速度大约快了3.2倍。
runtime.duffzero
,并在AX中使用一些其他值而不是0
。另请参见mkduff.go。 - thwdmemset
еђЊж ·жІЎжњ‰е°†ж‰Ђжњ‰е…ѓзґ е€ќе§‹еЊ–дёє1
гЂ‚ - milleniumbugmemset
和循环性能的时间数据吗? - Akavall