Как передать константный указатель большой структуры в функцию или go канал. Цель этого запроса:
- Избегать случайного изменения указателя функцией
- Избегать копирования объекта структуры при передаче в функцию / канал
Эта функциональность очень распространена в C ++, C#, Java, но как мы можем добиться того же в golang?
============== Обновление 2 ===================
Спасибо, @zarkams, @mkopriva и @peterSO. Оптимизация компилятора привела к одинаковому результату как byValue (), так и byPointer (). Изменили функции byValue () и byPointer (), добавив data.array [0] = reverse (data.array [0]) , просто чтобы компилятор не делал функции встроенными.
func byValue(data Data) int {
data.array[0] = reverse(data.array[0])
return len(data.array)
}
func byPointer(data *Data) int {
data.array[0] = reverse(data.array[0])
return len(data.array)
}
func reverse(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
После этого выполнения тестов передача по указателю была намного эффективнее, чем передача по значению.
C:\Users\anikumar\Desktop\TestGo>go test -bench=.
goos: windows
goarch: amd64
BenchmarkByValue-4 18978 58228 ns/op 3 B/op 1 allocs/op
BenchmarkByPointer-4 40034295 33.1 ns/op 3 B/op 1 allocs/op
PASS
ok _/C_/Users/anikumar/Desktop/TestGo 3.336s
C:\Users\anikumar\Desktop\TestGo>go test -gcflags -N -run=none -bench=.
goos: windows
goarch: amd64
BenchmarkByValue-4 20961 59380 ns/op 3 B/op 1 allocs/op
BenchmarkByPointer-4 31386213 36.5 ns/op 3 B/op 1 allocs/op
PASS
ok _/C_/Users/anikumar/Desktop/TestGo 3.909s
============= Update = ==================
На основе отзывов от @zerkms я создал тест, чтобы найти разницу в производительности между копией по значению и копией по указатель.
package main
import (
"log"
"time"
)
const size = 99999
// Data ...
type Data struct {
array [size]string
}
func main() {
// Preparing large data
var data Data
for i := 0; i < size; i++ {
data.array[i] = "This is really long string"
}
// Starting test
const max = 9999999999
start := time.Now()
for i := 0; i < max; i++ {
byValue(data)
}
elapsed := time.Since(start)
log.Printf("By Value took %s", elapsed)
start = time.Now()
for i := 0; i < max; i++ {
byPointer(&data)
}
elapsed = time.Since(start)
log.Printf("By Pointer took %s", elapsed)
}
func byValue(data Data) int {
data.array[0] = reverse(data.array[0])
return len(data.array)
}
func byPointer(data *Data) int {
data.array[0] = reverse(data.array[0])
return len(data.array)
}
func reverse(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
После 10 итераций вышеприведенной программы я не нашел никакой разницы во времени выполнения.
C:\Users\anikumar\Desktop\TestGo>TestGo.exe
2020/02/16 15:52:03 By Value took 5.2798936s
2020/02/16 15:52:09 By Pointer took 5.3466306s
C:\Users\anikumar\Desktop\TestGo>TestGo.exe
2020/02/16 15:52:18 By Value took 5.3596692s
2020/02/16 15:52:23 By Pointer took 5.2724685s
C:\Users\anikumar\Desktop\TestGo>TestGo.exe
2020/02/16 15:52:29 By Value took 5.2359938s
2020/02/16 15:52:34 By Pointer took 5.2838676s
C:\Users\anikumar\Desktop\TestGo>TestGo.exe
2020/02/16 15:52:42 By Value took 5.8374936s
2020/02/16 15:52:49 By Pointer took 6.9524342s
C:\Users\anikumar\Desktop\TestGo>TestGo.exe
2020/02/16 15:53:40 By Value took 5.4364867s
2020/02/16 15:53:46 By Pointer took 5.8712875s
C:\Users\anikumar\Desktop\TestGo>TestGo.exe
2020/02/16 15:53:54 By Value took 5.5481591s
2020/02/16 15:54:00 By Pointer took 5.5600314s
C:\Users\anikumar\Desktop\TestGo>TestGo.exe
2020/02/16 15:54:10 By Value took 5.4753771s
2020/02/16 15:54:16 By Pointer took 6.4368084s
C:\Users\anikumar\Desktop\TestGo>TestGo.exe
2020/02/16 15:54:24 By Value took 5.4783356s
2020/02/16 15:54:30 By Pointer took 5.5312314s
C:\Users\anikumar\Desktop\TestGo>TestGo.exe
2020/02/16 15:54:39 By Value took 5.4853542s
2020/02/16 15:54:45 By Pointer took 5.5541164s
C:\Users\anikumar\Desktop\TestGo>TestGo.exe
2020/02/16 15:54:57 By Value took 5.4633856s
2020/02/16 15:55:03 By Pointer took 5.4863226s
Похоже @zerkms прав. Это не из-за языка, это из-за современного оборудования.