在本文中,我们展示了如何在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)
一个hello
goroutine是用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
函数中,我们创建了五个消息并通过通道将它们发送到main
goroutine。当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教程。