在本文中,我们展示了如何在Golang中使用通道。
$ go version go version go1.18.1 linux/amd64
我们使用Go版本1.18。
Goroutine是一个轻量级的执行线程。它是一个与其他正在运行的代码同时运行的函数。
通道用于goroutine之间的通信。
渠道功能和运营商
在本节中,我们介绍了与通道相关的函数和运算符。
c := make(chan int)
频道是使用make函数和chan关键字创建的。频道被赋予一种类型。
<-运算符用于读取通道和写入通道。
c <- v
此行将值写入通道。
<- c
此行从通道读取值。
close(c)
使用close函数关闭通道。
for e := range(c) {
fmt.Println(e)
}
我们可以使用range迭代通道中的值。
len(c)
len函数返回已经成功发送到通道但还没有被取出的元素个数。
单向通道
默认情况下,通道是双向的。它们均可用于发送和接收数据。
rc chan<- int
将箭头运算符放在chan关键字的右侧,我们创建了一个只接收通道。
wc <-chan int
将箭头运算符放在chan关键字的左侧,我们创建了一个只发送通道。
Go通道简单示例
下面是一个使用通道的简单示例。
package main
import "fmt"
func main() {
c := make(chan string)
go func() {
c <- "an old falcon"
}()
msg := <-c
fmt.Println(msg)
}
在程序中,我们有两个协程。一个是使用go关键字创建的;main函数也是一个goroutine。
c := make(chan string)
我们创建一个字符串类型的通道。
go func() {
c <- "an old falcon"
}()
在匿名goroutine中,我们向通道发送字符串消息。
msg := <-c
在主goroutine中,我们从通道中读取值。
$ go run main.go an old falcon
去通道死锁
当代码在使用通道时被阻塞时会发生通道死锁。当我们尝试从打开的空通道中读取或尝试写入打开的已满通道时,通道被阻塞。
package main
import "fmt"
func main() {
c := make(chan string)
c <- "an old falcon"
msg := <-c
fmt.Println(msg)
}
这个程序以死锁结束。
c <- "an old falcon"
我们将值写入通道。channel阻塞等待,直到清空。因此,从channel中读取并清空的那条线没有到达。这种情况导致死锁。
$ go run main.go fatal error: all goroutines are asleep - deadlock! ...
去通道范围
我们可以使用range关键字来遍历发送到通道的数据。
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan string)
go hello("Martin", c)
for msg := range c {
fmt.Println(msg)
}
}
func hello(name string, c chan string) {
for i := 0; i < 5; i++ {
msg := fmt.Sprintf("Hello %s!", name)
c <- msg
time.Sleep(time.Millisecond * 500)
}
close(c)
}
在程序中,我们向一个频道发送了五条消息。
go hello("Martin", c)
一个hellogoroutine是用go创建的。我们将通道作为参数传递。
for msg := range c {
fmt.Println(msg)
}
使用range关键字,我们遍历消息并将它们打印到控制台。
func hello(name string, c chan string) {
for i := 0; i < 5; i++ {
msg := fmt.Sprintf("Hello %s!", name)
c <- msg
time.Sleep(time.Millisecond * 500)
}
close(c)
}
在hello函数中,我们创建了五个消息并通过通道将它们发送到maingoroutine。当goroutine完成时,我们用close关闭通道。
$ go run main.go Hello Martin! Hello Martin! Hello Martin! Hello Martin! Hello Martin!
单向通道示例
在下面的例子中,我们使用单向通道。
package main
import "fmt"
func main() {
c1 := make(chan int)
c2 := make(chan int)
go power(c2, c1)
go power(c2, c1)
go power(c2, c1)
c2 <- 2
fmt.Println(<-c1)
c2 <- 4
fmt.Println(<-c1)
c2 <- 5
fmt.Println(<-c1)
}
func power(wc <-chan int, rc chan<- int) {
num := <-wc
res := num * num
rc <- res
}
在程序中,我们有一个power函数,它接受一个只写的wc通道和一个只读的rc通道。
$ go run main.go 4 16 25
在本文中,我们使用了Go通道。
列出所有Go教程。
