在查看一些Go语言代码时,我发现了以下代码:
ch := make(chan int)
我在一个在线教程中查找了Go Channels是如何工作的:
https://tour.golang.org/concurrency/2
但我觉得这个例子不清楚。
有人能给予我一个简单的解释和使用通道的例子吗?
在查看一些Go语言代码时,我发现了以下代码:
ch := make(chan int)
我在一个在线教程中查找了Go Channels是如何工作的:
https://tour.golang.org/concurrency/2
但我觉得这个例子不清楚。
有人能给予我一个简单的解释和使用通道的例子吗?
4条答案
按热度按时间ru9i0ody1#
chan是Golang的一个频道,简单的说,你可以把它想象成一个盒子,你把一个东西放在盒子的一端,然后从另一端拿出来。
无缓冲通道
缓冲通道
这是我为你写的一小段代码,让你了解通道。现在改变go例程的顺序,看看输出。每次的输出可能不同。
为了更好地理解,请访问这个博客,其中介绍了GUI中的go例程和通道。
访视http://divan.github.io/posts/go_concurrency_visualize/
ercv8c1e2#
我认为规范对此非常明确。规范:通道类型:
通道提供了一种机制,用于通过发送和接收指定元素类型的值来并发执行函数以进行通信。
当你有多个同时执行的goroutine时,通道提供了最简单的方式让goroutine之间进行通信。
一种通信方式是通过一个“共享”变量,这个变量对两个goroutine都是可见的,但这需要适当的锁定/同步访问。
相反,围棋偏爱渠道。通过交流分享:
不通过共享内存进行通信;而是通过通信来共享存储器。
因此,你可以创建一个通道(对两个goroutine都是可见的),而不是把消息放到一个共享的切片中。在没有任何外部同步/锁的情况下,一个goroutine可以通过这个通道发送消息(值),而另一个goroutine可以接收它们。
在任何给定的时间,只有一个goroutine可以访问这个值,数据竞争是不会发生的。
因此,实际上,任何数量的goroutine都可以在同一个通道上发送值,也可以从同一个通道上接收值,而不需要任何进一步的同步。If I am using channels properly should I need to use mutexes?
通道示例
下面我们来看一个例子,我们启动了两个额外的goroutine来进行并发计算,我们将一个数字传递给第一个goroutine,第一个goroutine将这个数字加1,然后将结果传递给第二个goroutine,第二个goroutine将接收到一个数字,将这个数字乘以10,然后将结果传递给结果通道:
以下是它的调用/使用方式:
通过通道进行通信也会考虑goroutine之间的等待,在这个例子中,这意味着
MulBy10()
会等待AddOne()
发送递增后的数字,而main()
会等待MulBy10()
之后再打印结果。输出如预期的结果(在Go Playground上试试):语言支持
有许多语言结构可方便地使用通道,例如:
for ... range
循环处理从通道接收的值,直到通道关闭。select
语句可用于列出多个通道操作,例如 * 在通道上发送 * 和 * 从通道接收 *,并且将选择可以继续而不阻塞的操作(如果有多个可以继续的操作,则随机选择;并且如果没有就绪则将阻塞)。v, ok := <-ch
len()
函数告诉队列中的元素数(未读);构建的cap()
函数返回信道缓冲器容量。其他用途
更实际的例子是如何使用通道来实现worker pool。类似的用法是从producer to consumer(s)分配值。
另一个实际示例是实现memory pool using buffered channels。
另一个实际的例子是一个优秀的代理实现。
通道通常用于超时一些阻塞操作,利用
time.After()
返回的通道,该通道在指定的延迟/持续时间后“触发”(“触发”意味着将在其上发送一个值)。请参见以下示例进行演示(在Go Playground上尝试):它可以用来等待某个值的最长等待时间,但是如果其他goroutine在这个时间内不能提供这个值,我们可以决定做其他事情来代替。
另外,一种特殊的通信形式可能只是发出一些操作完成的信号(实际上不发送任何“有用”的数据)。这种情况可以通过一个具有任何元素类型的通道实现,例如
chan int
,并在其上发送任何值,例如0
。但由于发送的值不包含任何信息,因此您可以像chan struct{}
那样声明它。或者更好,如果你只需要一个一次性的信令,你可以关闭通道,使用for ... range
在另一端截取它,或者从它接收(因为从一个关闭的通道接收会立即进行,产生元素类型的零值)。还要知道,即使一个通道可以用于这种信令,也有一个更好的选择:sync.WaitGroup
.进一步阅读
为了避免令人惊讶的行为,有必要了解渠道原则:How does a non initialized channel behave?
The Go Blog: Share Memory By Communicating
The Go Blog: Go Concurrency Patterns: Pipelines and cancellation
The Go Blog: Advanced Go Concurrency Patterns
Ardan labs: The Nature Of Channels In Go显示器
gtlvzcf83#
这一概念与Unix/Linux从一开始就有的概念非常相似:* 管道。*
这是一个可靠的进程间/线程间通信工具,内置于该语言中。非常方便。
9w11ddsr4#
如果你想让goroutine之间相互发送信号,可以使用通道。
1.给另一个goroutine发信号,让它开始执行任务。
1.等待其他goroutine结束任务。
1.通过关闭通道来通知其他goroutine停止工作。这里还有其他类似的场景。https://www.ardanlabs.com/blog/2017/10/the-behavior-of-channels.html
如果你想让goroutine进行通信,可以使用通道,也可以不使用数据。