icz*_*cza 41
我认为这个规格非常明确.规格:渠道类型:
当您有多个同时执行的goroutine时,通道提供了允许goroutine相互通信的最简单方法.
一种通信方式是通过两个goroutine可见的"共享"变量,但这需要适当的锁定/同步访问.
不要通过共享内存进行通信; 相反,通过沟通分享记忆.
因此,不是将消息放入共享切片,例如,您可以创建一个通道(两个goroutine都可见),并且没有任何外部同步/锁定,一个goroutine可以通过通道发送消息(值),另一个goroutine可以接收他们.
在任何给定时间,只有一个goroutine可以访问该值.根据设计,数据竞争不会发生.
所以事实上,任何数量的goroutine都可以在同一个通道上发送值,任何数量的goroutine都可以从中接收值,仍然没有任何进一步的同步.有关详细信息,请参阅相关问题:如果我正确使用频道,是否需要使用互斥锁?
频道示例
让我们看一个例子,我们为并发计算目的开始另外两个goroutine.我们将一个数字传递给第一个数字,它会增加1,并在第二个通道上传递结果.第二个goroutine将收到一个数字,乘以10并将其传递到结果通道:
func AddOne(ch chan<- int, i int) {
i++
ch <- i
}
func MulBy10(ch <-chan int, resch chan<- int) {
i := <-ch
i *= 10
resch <- i
}
这是如何调用/使用它:
func main() {
ch := make(chan int)
resch := make(chan int)
go AddOne(ch, 9)
go MulBy10(ch, resch)
result := <-resch
fmt.Println("Result:", result)
}
MulBy10()AddOne()main()MulBy10()
Result: 100
语言支持
有许多语言结构可以方便地使用频道,例如:
for ... rangeselectv, ok := <-chlen()cap()
其他用途
有关更实际的示例,请参阅如何使用通道实现工作池.类似的用途是将值从生产者分配给消费者.
另一个实际示例是使用缓冲通道实现内存池.
另一个实际的例子是经纪人的优雅实施.
time.After()
ch := make(chan int)
select {
case i := <-ch:
fmt.Println("Received:", i)
case <-time.After(time.Second):
fmt.Println("Timeout, no value received")
}
它可用于等待某个值的最大时间量,但如果其他goroutine无法提供该值,我们可能会决定做其他事情.
chan int0chan struct{}for ... rangesync.WaitGroup
进一步阅读
值得了解通道公理以避免出现令人惊讶的行为:非初始化通道如何表现?
- 我喜欢这个答案,尤其是有关使用time.After(time.Second)的内容。我不知道可以做到这一点。 (3认同)