最简单的循环解决方案如下所示:
func memsetLoop(a []int, v int) {
for i := range a {
a[i] = v
}
}
没有memset
标准库支持,但我们可以使用内置的copy() https://golang.org/pkg/builtin/#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() http://golang.org/pkg/bytes/#Repeat。如果您只想创建一个新的[]byte
填充相同的值,您可以使用bytes.Repeat()
功能。您不能将其用于除以下之外的现有切片或切片[]byte
,为此您可以使用所提供的memsetRepeat()
.
如果是小片的话memsetRepeat()
可能会慢于memsetLoop()
(但如果是小切片,这并不重要,它会立即运行)。
由于使用快速copy()
, memsetRepeat()
如果元素数量增加,速度会快得多。
对这 2 个解决方案进行基准测试:
var a = make([]int, 1000) // Size will vary
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
10,000 个元素:快约 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 倍.