golang channel用法
更新时间:2023-07-09什么是 golang channel
Go语言的channel是一种独特的数据结构,在实现并发的时候非常重要。channel是Go语言通信的核心,它也是Go语言的独特之处之一。一般来说,channel可以理解为一个通道,通过它可以实现不同协程之间的通信和同步。
package main
import "fmt"
func main() {
// 创建一个通道
ch := make(chan int)
// 向通道发送值
ch <- 10
// 从通道接收值
num := <-ch
fmt.Println(num)
}
上面的代码展示了如何使用make创建一个channel,然后向通道发送值,最后从通道中接收值。这里需要注意的是,向通道发送值和从通道接收值都是需要采用`<-`操作符的。如果没有接收方,发送操作就会一直阻塞。
channel的阻塞与非阻塞
Go语言中的channel分为同步和异步两种方式,也就是阻塞和非阻塞。默认情况下,channel是同步方式:发送方发送数据后必须等到接收方接收完毕后才能继续发送。
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
// 同步方式
go func() {
ch <- 10
fmt.Println("发送完毕")
}()
time.Sleep(2 * time.Second)
num := <-ch
fmt.Println(num)
}
上面的代码展示了一个同步方式的channel:发送方发送数据后,必须等待接收方接收完毕后才会打印“发送完毕”。在此期间,主协程一直处于阻塞状态。
如果想要使用异步方式的channel,可以采用非阻塞的方式。这时候,发送方可以直接向通道中发送数据,接收方可直接读取数据(不需要等待发送方完成)。
package main
import (
"fmt"
)
func main() {
ch := make(chan int, 1)
// 异步方式
go func() {
ch <- 10
fmt.Println("发送完毕")
}()
num := <-ch
fmt.Println(num)
}
上面的代码展示了一个异步方式的channel:发送方向通道发送数据后,直接打印“发送完毕”,而接收方在自己准备好之后去读取数据即可,不需要等待。
channel 的方向
Go语言中的channel还可以指定方向,使得发送方只能向通道发送数据,而接收方只能从通道中读取数据。这样可以增强代码的安全性和可读性,防止出现不必要的错误。
package main
import "fmt"
func send(ch chan<- int, val int) {
ch <- val
}
func receive(ch <-chan int) {
fmt.Println(<-ch)
}
func main() {
ch := make(chan int)
go send(ch, 10)
receive(ch)
}
上面的代码定义了两个函数send和receive: send函数只能用于向通道中发送数据(而不是接收数据),而receive函数只能用于从通道中接收数据(而不是发送数据)。如果尝试在send函数中读取数据,或在receive函数中发送数据,则编译器将会报错。
channel 关闭
Go语言中的channel还支持关闭操作,通过关闭无缓冲的channel来表示数据已经传送完成。一般来说,在发送方关闭channel之后,接收方将会收到非阻塞的零值。但是在通道中还有剩余元素的情况下,接收方还是可以继续接收完所有元素。
package main
import "fmt"
func main() {
ch := make(chan int)
go func() {
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)
}()
for val := range ch {
fmt.Println(val)
}
}
上面的代码展示了在for-range循环中使用通道的方式。在发送方向通道中发送完5个数据后,发送方调用close函数,标志着数据已发送完毕。在主协程中,通过for-range循环遍历通道,并且如果通道已关闭则退出循环体。