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
In Golang, or Go, channels are a means through which different goroutines communicate. Think of them as pipes through which you can connect with different concurrent goroutines. The communication is bidirectional by default, meaning that you can send and receive values from the same channel.
Closing a channel indicates that no more values will be sent on it. This can be useful to communicate completion to the channel's receivers. In this example we'll use a jobs channel to communicate work to be done from the main() goroutine to a worker goroutine.
A channel in Go refers to a technique through which goroutines can communicate. Simply put, a channel is a pipe through which you can connect concurrent goroutines, allowing for communication. Communication between goroutines is bidirectional.
Channel operation (i.e. write or read) are blocking in nature. This means: When we send data into the channel using a GoRoutine, it will be blocked until the data is consumed by another GoRoutine. When we receive data from channel using a GoRoutine, it will be blocked until the data is available in the channel.
The Go Programming Language Specification
Send statements
A send statement sends a value on a channel. The channel expression must be of channel type, the channel direction must permit send operations, and the type of the value to be sent must be assignable to the channel's element type.
It's a copy because the value is sent to the channel by assignment to the channel's element type. If the value is a struct, then the struct is copied. If the value is a pointer to a struct, then the pointer to the struct is copied.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With