Go中 channel的使用
创始人
2024-06-03 00:58:44
0

文章目录

    • 背景
    • channel 简介
    • 使用说明
      • 声明
      • 发送和接受数据
      • 关闭channel
    • 使用示例

背景

使用 sync 包和 context 包的工具可以实现多个协程之间互相协作, 但是没有一种很好的方式解决多个协程之间通信的问题. golang 作者 Rob Pike 说过一句话,不要通过共享内存来通信,而应该通过通信来共享内存. 表示了Go中不希望通过共享区域存储数据来实现多个协程的通信.

channel 简介

可以把channel 看作 是一种先进先出的双向队列, 并且是并发安全,同一时刻,运行时只会执行一个对同一 channel 操作(发送或接收)中的某一个操作(发送或接收),即操作(发送或接收)之间是互斥的。并且对同一 channel 中的同一个元素执行的发送和接收操作之间也是互斥的。

使用说明

声明

生命使用 make 函数, 第一个参数必须是chan 数据类型 第二个可选的int 类型, 如果没有给定第二个参数,该 channel 为无缓冲 channel, 即 默认为0。反之为有缓冲 channel。参数表示缓冲区的大小, 即除了被等待读取的数据外, 还可以存储的容量, 那么队列总长度, 就是第二个参数 + 1.

// 声明一个 int 类型的无缓冲 channel
c1 := make(chan int)
// 声明一个 int 类型的有缓冲 channel,容量 cap 为 5, 队列可以存储 6 个数据
c2 := make(chan int, 5)

单向 channel 创建, 默认创建的 channel 是双向的, 即双方都可以写入和写出, 单项写入channel 是 chan<- int 单向输出 channel 是 <-chan int

发送和接受数据

发送和接受数据都使用 <- 区别是,发送时操作符在 channel 类型变量名的右边,接收时操作符在 channel 类型变量的左边。

c := make(chan int, 2)
// send
c <- 1
c <- 2
// 接受并且输出结果
fmt.Println(<- c)
// 接收并且赋值给变量
x <- c

关闭channel

使用close(chan变量) 方法的方式关闭 channel, 在读取的时候, 第二个参数可以表示是否关闭了 channel, 为 true 就表示 channel 没有关闭

c := make(chan int, 5)
close(c)
val, ok := <- c
// ok为true 就表示还没有关闭
fmt.Println(val, ok)

使用示例

我们要听从老板的指示, 老板让做啥就做啥, 我们这里使用单向的队列实现, 老板发送信息, 员工接收信息.

package mainimport ("fmt""time"
)var c = make(chan string,2)// 返回只能写入的类型
func getSender() chan<- string {return c
}
// 返回只能读取的类型
func getRec() <-chan string {return c
}// 并发执行任务 1 和任务 2
func main() {// 小卡拉准备接活干rec := getRec()go func() {for i := range rec {fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "小卡拉开始干", i)time.Sleep(2 * time.Second)fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "小卡拉干完了", i)}}()// 老板派活send := getSender()arr := [...]string{"拿快递", "点外卖", "泡咖啡", "写PPT", "写总结"}for _, data := range arr {fmt.Println(time.Now().Format("2006-01-02 15:04:05"), "老板安排", data)send <- data}close(send)time.Sleep(15* time.Second)
}

如上所示,我们创建可一个缓存区长度为2 的有缓存channel, 之后先启动一个员工的协程, 等待处理数据, 后面老板开始往队列写入摇杆的活. 执行结果如下
在这里插入图片描述
可以看待, 老板发布了三个任务就不能继续发布了, 必须等待员工取走一个才行, 这里表明第一个是等待接受的数据, 后面两个是缓存区的数据, 对应缓存区大小为2. 再往后就是员工取一个, 老板发布一个. 这样就完成了两个协程的通信

还有老板的协程和员工的协程分别从getSendergetRec拿到的只能写入的和只能读取的channel. 我们试试往只能读取的channel 写入会发生什么呢? 比如员工要反馈, 不想干了.
在这里插入图片描述
在这里插入图片描述

会发现直接编译错误.

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...