在查看一些golang代码时,我发现了以下内容:
ch := make(chan int)
Run Code Online (Sandbox Code Playgroud)
我在golang Chanels的在线教程中查了解:
https://tour.golang.org/concurrency/2
但我觉得这个例子不清楚.
有人可以给我一个简单的解释和使用频道的例子吗?
shi*_*ngh 47
chan是Golang的一个频道.简单来说,你可以认为它是一个盒子,你把一个项目放在一端,然后从另一端挑选它.(顺序没关系)类似的东西
无缓冲的频道
缓冲频道
这是我为您理解频道而编写的小代码.现在改变go例程的顺序并查看输出.每次输出可能不同.
package main
import (
"fmt"
"time"
)
func main() {
messages := make(chan int)
go func() {
time.Sleep(time.Second * 3)
messages <- 1
}()
go func() {
time.Sleep(time.Second * 2)
messages <- 2
}()
go func() {
time.Sleep(time.Second * 1)
messages <- 3
}()
go func() {
for i := range messages {
fmt.Println(i)
}
}()
go func() {
time.Sleep(time.Second * 1)
messages <- 4
}()
go func() {
time.Sleep(time.Second * 1)
messages <- 5
}()
time.Sleep(time.Second * 5)
}
Run Code Online (Sandbox Code Playgroud)
为了更好地理解,请访问此博客,其中在GUI中描述了例程和通道.
访问http://divan.github.io/posts/go_concurrency_visualize/
icz*_*cza 41
我认为这个规格非常明确.规格:渠道类型:
当您有多个同时执行的goroutine时,通道提供了允许goroutine相互通信的最简单方法.
一种通信方式是通过两个goroutine可见的"共享"变量,但这需要适当的锁定/同步访问.
相反,Go赞成频道.引自有效围棋:通过沟通分享:
不要通过共享内存进行通信; 相反,通过沟通分享记忆.
因此,不是将消息放入共享切片,例如,您可以创建一个通道(两个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
}
Run Code Online (Sandbox Code Playgroud)
这是如何调用/使用它:
func main() {
ch := make(chan int)
resch := make(chan int)
go AddOne(ch, 9)
go MulBy10(ch, resch)
result := <-resch
fmt.Println("Result:", result)
}
Run Code Online (Sandbox Code Playgroud)
通过渠道进行沟通也会照顾到彼此等待的goroutine.在此示例中,它表示MulBy10()
将等待直到AddOne()
递送递增的数字,并将在打印结果之前main()
等待MulBy10()
.按预期输出(在Go Playground上试试):
Result: 100
Run Code Online (Sandbox Code Playgroud)
有许多语言结构可以方便地使用频道,例如:
for ... range
一个通道上循环通过从一个信道接收的值,直到该信道被关闭.select
语句可用于列出多个通道操作,例如在通道上发送和从通道接收,并且将选择可以无阻塞地进行的通道操作(如果有多个可以继续,则随机选择;如果没有,则将阻止准备).v, ok := <-ch
len()
函数告诉排队的元素数(未读); 构建cap()
函数返回通道缓冲区容量.有关更实际的示例,请参阅如何使用通道实现工作池.类似的用途是将值从生产者分配给消费者.
另一个实际的例子是经纪人的优雅实施.
通道通常用于超时某些阻塞操作,利用返回的通道time.After()
,在指定的延迟/持续时间后"触发"("触发"表示将在其上发送值).请参阅此示例以进行演示(在Go Playground上尝试):
ch := make(chan int)
select {
case i := <-ch:
fmt.Println("Received:", i)
case <-time.After(time.Second):
fmt.Println("Timeout, no value received")
}
Run Code Online (Sandbox Code Playgroud)
它可用于等待某个值的最大时间量,但如果其他goroutine无法提供该值,我们可能会决定做其他事情.
另外一种特殊形式的通信可能只是表示某些操作的完成(没有实际发送任何"有用的"数据).这种情况可以由具有任何元素类型的信道实现,例如chan int
,并且在其上发送任何值,例如0
.但由于发送的值不包含任何信息,您可以声明它chan struct{}
.或者甚至更好,如果你只需要一次性信令,你可以关闭可以在另一侧使用for ... range
或从中接收的信道(当从一个封闭的信道接收时立即进行,产生零值)元素类型).还要知道即使某个信道可以用于这种信令,也有更好的选择:sync.WaitGroup
.
值得了解通道公理以避免出现令人惊讶的行为:非初始化通道如何表现?
Go Blog:Go Concurrency Patterns:Pipelines and cancellation
Go Blog:Advanced Go Concurrency Patterns
归档时间: |
|
查看次数: |
9427 次 |
最近记录: |