在golang中,一个活动单元被称为goroutine,通过go
关键字来启动一个goroutine并立刻返回。
f() // 调用f(),并等待结果
go f() // 新建一个调用f()的goroutine,不用等待
main函数运行在主goroutine中,当main函数返回时,所有的goroutine都将终结,进程将退出,释放所有资源。
goroutine的粒度是一个函数,这个函数无需实现任何接口,也无需绑定到任何类中。我们也可以通过go
关键字直接运行一个匿名函数,就像下面这样
go func() {
// do something async
}()
ch := make(chan int)
上面的代码创建了一个chan int
类型的通道。
通道有三个操作,发送、接收和关闭。
ch <- x // 将x发送给ch通道
x, ok = <- ch // 从ch通道中接收一个值,并赋值给x。 ok为false时表示通道已关闭,此时的x为零值。
<- ch // 从ch通道中接收一个值,并丢弃
close(ch) // 关闭通道
向已关闭的通道发送消息将会导致应用宕机,从已关闭的通道中读取消息的话,后续的所有操作都顺畅进行,只是获取到的是零值。
下面的demo中,将创建三个goroutine,第一个goroutine负责生产数字,第二个goroutine负责做平方,第三个goroutine负责打印数字,它们之间使用两个通道进行通信,这比较像linux中的pipeline(管道)。当第一个goroutine生产10个数字时候,通道关闭,当第二个goroutine发现第一个通道关闭后,也关闭第二个通道。
func main() {
naturals := make(chan int)
squares := make(chan int)
go func() {
for i := 0; i < 10; i++ {
naturals <- i
time.Sleep(time.Millisecond * 100)
}
close(naturals)
}()
go func() {
for {
x, ok := <-naturals
if !ok {
close(squares)
break
}
squares <- x * x
}
}()
for x := range squares {
fmt.Println(x)
}
fmt.Println("done")
}
值得注意的是,第二个goroutine是手动的捕获到了通道已关闭的时机,而第三个goroutine则借助了range
,当通道关闭时(即接收到的第二个参数为false时),循环自动结束。
注意:当通道未关闭,并且没有发送者继续向通道发送消息时,range函数会阻塞死。
我们可以通过 chan<-
来表示一个只能发送的通道,通过<-chan
来表示一个只能接收的通道。
我们将上面的代码改造一下,通过go关键字来调用一个命名函数,并使用单向通道:
func generateNumbers(outputCh chan<- int) {
for i := 0; i < 10; i++ {
outputCh <- i
time.Sleep(time.Millisecond * 100)
}
close(outputCh)
}
func squareNumbers(inputCh <-chan int, outputCh chan<- int) {
for x := range inputCh {
outputCh <- x * x
}
close(outputCh)
}
func printNumbers(inputCh <-chan int) {
for x := range inputCh {
fmt.Println(x)
}
}
func main() {
naturals := make(chan int)
squares := make(chan int)
go generateNumbers(naturals)
go squareNumbers(naturals, squares)
printNumbers(squares)
fmt.Println("done")
}
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://laozhu.blog.csdn.net/article/details/121323924
内容来源于网络,如有侵权,请联系作者删除!