If a large struct is sent over a channel in Go, is it actually copied between goroutines?
For example, in the code below, will Go actually copy all largeStruct data between goroutines producer and consumer?
package main
import (
"fmt"
"sync"
)
type largeStruct struct {
buf [10000]int
}
func main() {
ch := make(chan largeStruct)
wg := &sync.WaitGroup{}
wg.Add(2)
go consumer(wg, ch)
go producer(wg, ch)
wg.Wait()
}
func producer(wg *sync.WaitGroup, output chan<- largeStruct) {
defer wg.Done()
for i := 0; i < 5; i++ {
fmt.Printf("producer: %d\n", i)
output <- largeStruct{}
}
close(output)
}
func consumer(wg *sync.WaitGroup, input <-chan largeStruct) {
defer wg.Done()
i := 0
LOOP:
for {
select {
case _, ok := <-input:
if !ok {
break LOOP
}
fmt.Printf("consumer: %d\n", i)
i++
}
}
}
Playground: http://play.golang.org/p/fawEQnSDwB
Yes, everything is a copy in Go, you can easily work around that by changing the channel to use a pointer (aka chan *largeStruct
).
// demo: http://play.golang.org/p/CANxwt8s2B
As you can see, the pointer to v.buf
is different in each case, however if you change it to chan *largeStruct
, the pointers will be the same.
@LucasJones provided a little easier to follow example: https://play.golang.org/p/-VFWCgOnh0
As @nos pointed out, there's a potential race if you modify the value in both goroutines after sending it.