在Go中,可以通过通道发送任何类型的值:int、struct、指针、接口等。
代码示例:
type Data struct { N int } c := make(chan Data) d := Data{N: 1} c <- d // 整个结构体被复制 p := &Data{N: 3} c2 := make(chan *Data) c2 <- p // 通道发送的是指向同一对象的指针
如果通过通道传递一个包含指针字段的结构体——在通道两端修改该字段会产生竞争条件吗?
回答:
示例:
type Box struct { Ptr *int } x := 10 chanBox := make(chan Box) chanBox <- Box{Ptr: &x} // 发送方和接收方都可以访问x!
故事
在分布式队列中,经常出现“随机”崩溃和奇怪的任务结构值。结果发现,通过通道传递了指向共享结构的指针,这些结构在多个goroutine中并行修改。决定通过传递数据副本来解决。
故事
异步消息处理在内部使用了指向共享数组的切片指针,导致通过通道并行传递的同一内存部分从不同位置被修改,造成隐蔽的bug和数据损坏。
故事
在推送通知服务中,通过通道传递指向对象的引用,之后被goroutine处理。在同时结束工作和关闭通道时,一些结构仍在修改,导致崩溃或数据竞争。通过在发送前复制结构来解决。