Ответ 1
Простейшее решение с циклом будет выглядеть так:
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()
будет намного быстрее, если число элементов растет.
Сравнивая эти 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 раза быстрее.