go中是否有memset的模拟? [英] Is there analog of memset in go?
问题描述
在 C++ 中,我可以使用 memset:
In C++ I can initialize an array with some value using memset:
const int MAX = 1000000;
int is_prime[MAX]
memset(is_prime, 1, sizeof(is_prime))
memset 所做的,粗略地可以描述为用一些值填充数组,但这样做真的非常快.
What memset does, crudely can be described as filling the array with some value, but doing this really really fast.
在 go 中我可以做 is_prime := make([]int, 1000000)
,但这将创建一个全为 0 的切片,以类似的方式我可以使用 new([1000000]int)
,但没有任何东西可以让我创建一个包含全 1 或任何其他非零元素的数组/切片.
In go I can do is_prime := make([]int, 1000000)
, but this will create a slice with all 0, in the similar manner I can use new([1000000]int)
, but nothing will allow me to create an array/slice with all 1 or any other non-zero element.
当然我可以稍后使用循环来用值填充它,但是memset
的主要目的是它比循环快得多.
Of course I can use a loop to populate it with the value later, but the main purpose of memset
is that it is way way faster than the loop.
Go 程序员是否有 memset
模拟(将数组初始化为某个非零值的快速方法)?
So do Go programmers have a memset
analog (fast way of initializing array to some non-zero value)?
推荐答案
最简单的循环解决方案如下所示:
The simplest solution with a loop would look like this:
func memsetLoop(a []int, v int) {
for i := range a {
a[i] = v
}
}
标准库中没有 memset
支持,但我们可以利用内置的 copy()
高度优化.
There is no memset
support in the standard library, but we can make use of the built-in copy()
which is highly optimized.
我们可以手动设置第一个元素,然后使用copy()
开始将已经设置的部分复制到未设置的部分;其中已经设置的部分每次都越来越大(翻倍),所以迭代次数为log(n)
:
We can set the first element manually, and start copying the already set part to the unset part using copy()
; where the already set part gets bigger and bigger every time (doubles), so the number of iterations is 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()
.
This solution was inspired by the implementation of bytes.Repeat()
. If you just want to create a new []byte
filled with the same values, you can use the bytes.Repeat()
function. You can't use that for an existing slice or slices other than []byte
, for that you can use the presented memsetRepeat()
.
在小切片的情况下 memsetRepeat()
可能比 memsetLoop()
慢(但在小切片的情况下并不重要,它会在一瞬间).
In case of small slices memsetRepeat()
may be slower than memsetLoop()
(but in case of small slices it doesn't really matter, it will run in an instant).
由于使用了快速的 copy()
,如果元素数量增加,memsetRepeat()
会更快.
Due to using the fast copy()
, memsetRepeat()
will be much faster if the number of elements grows.
对这 2 个解决方案进行基准测试:
Benchmarking these 2 solutions:
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 倍
10,000 elements: ~2 times faster
BenchmarkLoop 200000 7029 ns/op
BenchmarkRepeat 500000 3544 ns/op
100,000 个元素:约快 1.5 倍
100,000 elements: ~1.5 times faster
BenchmarkLoop 20000 70671 ns/op
BenchmarkRepeat 30000 45213 ns/op
最高性能增益约为 3800-4000 个元素,速度约 3.2 倍.
The highest performance gain is around 3800-4000 elements where it is ~3.2 times faster.
这篇关于go中是否有memset的模拟?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!