您的位置 首页 golang

Go 语言入门与进阶:channel 实践

前文回顾

如果你还没有 Go 语言基础,建议阅读我的 从零学 Go。

本系列文章,我将会进一步加深对 Go 语言的讲解,更一步介绍 Go 中的包管理、反射和并发等高级特性。

了解完 Go 中 goroutine 的实践,本文将会重点介绍 channel 的使用和特点。

通道 channel

Go 中倡导使用 channel 作为 goroutine 之间同步和通信的手段。channel 类型属于引用类型,且每个 channel 只能传递固定类型的数据,channel 声明如下所示:

 var channelName chan T
复制代码  

我们通过 chan 关键字声明一个新的 channel,并且声明时指定 channel 内传输的数据类型 T。

channel 作为一个队列,它会保证数据收发顺序,总是遵循先入先出的原则进行;同时它也会保证同一时刻内有且仅有一个 goroutine 访问 channel 用于发送和获取数据。

从 channel 发送数据需要使用 <- 符号,如下所示:

 channel <- val
复制代码  

表示 val 将会发送到 channel 中,在 channel 被填满之后再往通道中将会阻塞当前 goroutine。而从 channel 读取数据也是使用符号 <-,只不过待接受的数据和 channel 的位置互换了,如下所示:

 val := <- channel
复制代码  

表示从 channel 中读取 val,如果 channel 中没有数据,将会阻塞读取的 goroutine 直到有数据被放入 channel。当然也可以在读取 channel 时立刻返回,如下所示:

 val, ok:= <- channel
复制代码  

这时需要检查 ok 是否为 true 用于判断是否读取到有效数据。

创建 channel 我们需要借助 make 函数对 channel 进行初始化,形式如下所示:

 ch := make(chan T, sizeOfChan)
复制代码  

在创建 channel 时需要指定 channel 传输的数据类型,可选指定 channel 的长度。如果不指定 channel 的长度,那么往 channel 中发送数据的 goroutine 将会被阻塞到数据被读取;而指定了长度的 channel 将会携带 sizeOfChan 的缓冲区,在缓冲区未满时发送数据不会被 channel 阻塞。无论 channel 是否携带缓冲区,读取的 goroutine 都会被阻塞直到 channel 中有数据可被读取。

接下来我们通过一个例子来实践 goroutine 和 channel 配合,我们将创建一个 channel 用于在两个 goroutine 中发送数据,其中一个 goroutine 从命令行读取输入发送到 channel 中,另一个 goroutine 循环从 channel 中读取数据并输出,代码如下所示:

 package main

import (
"bufio"
"fmt"
"os"
)

func printInput(ch chan string)  {
// 使用 for 循环从 channel 中读取数据
for val := range ch{
// 读取到结束符号
if val == "EOF"{
break
}
fmt.Printf("Input is %s\n", val)
}
}

func main()  {
// 创建一个无缓冲的 channel
ch := make(chan string)
go printInput(ch)

// 从命令行读取输入
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
val := scanner.Text()
ch <- val
if val == "EOF"{
break
}
}
// 程序最后关闭 ch
defer close(ch)

}
复制代码  

通过 go run 运行上述代码,在命令上中输入字符串,将会获取程序的反馈,如下所示:

 Hello
Input is Hello
Hi
Input is Hi
EOF
End the game!
复制代码  

channel 作为一个具备长度的容器,也是可以被遍历的。上述代码中,我们通过 for:range 语法从 channel 中循环读取数据.当 channel 中没有数据时,printInput 的 goroutine 将会被阻塞。代码的最后,我们还通过 defer close(ch) 关闭了创建的 channel,需要注意的是在 channel 关闭后不允许再往通道中放入数据,不然会抛出 panic;而从关闭的 channel 读取数据或者正在被阻塞的 goroutine 将会接受到零值,直接返回。

小结

本文主要介绍了协程 goroutine 的应用实践。Go 语言 channel 作为一个具备长度的容器,也是可以被遍历的。上述实践案例中,我们通过 for:range 语法从 channel 中循环读取数据.当 channel 中没有数据时,printInput 的 goroutine 将会被阻塞。代码的最后,我们还通过 defer close(ch) 关闭了创建的 channel,需要注意的是在 channel 关闭后不允许再往通道中放入数据,不然会抛出 panic;而从关闭的 channel 读取数据或者正在被阻塞的 goroutine 将会接受到零值,直接返回。

文章来源:智云一二三科技

文章标题:Go 语言入门与进阶:channel 实践

文章地址:https://www.zhihuclub.com/86300.shtml

关于作者: 智云科技

热门文章

网站地图