如果通过 Golang 通道发送,结构是不是实际上在 goroutine 之间复制?
Posted
技术标签:
【中文标题】如果通过 Golang 通道发送,结构是不是实际上在 goroutine 之间复制?【英文标题】:Is a struct actually copied between goroutines if sent over a Golang channel?如果通过 Golang 通道发送,结构是否实际上在 goroutine 之间复制? 【发布时间】:2016-06-21 02:42:27 【问题描述】:如果在 Go 中通过通道发送大型结构,它实际上是否在 goroutine 之间复制?
例如,在下面的代码中,Go 实际上会在 goroutines 生产者和消费者之间复制所有 largeStruct 数据吗?
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++
游乐场:http://play.golang.org/p/fawEQnSDwB
【问题讨论】:
另外,如果结构包含一个切片,`[]int',则按值传递切片(以及结构)的效果不会复制内部数组。我并不是说这是你的答案。 【参考方案1】:是的,Go 中的一切都是副本,您可以通过更改频道以使用指针(又名chan *largeStruct
)轻松解决这个问题。
// 演示:http://play.golang.org/p/CANxwt8s2B
如您所见,指向v.buf
的指针在每种情况下都不同,但是如果将其更改为chan *largeStruct
,则指针将相同。
@LucasJones 提供了一个更容易理解的示例:https://play.golang.org/p/-VFWCgOnh0
正如@nos 指出的那样,如果您在发送后修改两个 goroutine 中的值,则可能存在竞争。
【讨论】:
这是两种类型频道的游乐场演示:play.golang.org/p/-VFWCgOnh0 @LucasJones 我会将您的示例添加到帖子中以提高知名度。 如果您只发送一个指针,请注意潜在的竞争条件。你不想让两个 goroutine 都弄乱同一个结构【参考方案2】:The Go Programming Language Specification
Send statements
send 语句在通道上发送一个值。渠道表达 必须是通道类型,通道方向必须允许发送 操作,并且要发送的值的类型必须可分配给 频道的元素类型。
这是一个副本,因为值是通过分配给通道的元素类型而发送到通道的。如果该值是结构,则复制该结构。如果该值是指向结构的指针,则复制指向该结构的指针。
【讨论】:
以上是关于如果通过 Golang 通道发送,结构是不是实际上在 goroutine 之间复制?的主要内容,如果未能解决你的问题,请参考以下文章