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 写入会发生什么呢? 比如员工要反馈, 不想干了.
在这里插入图片描述
在这里插入图片描述

会发现直接编译错误.

相关内容

热门资讯

保存时出现了1个错误,导致这篇... 当保存文章时出现错误时,可以通过以下步骤解决问题:查看错误信息:查看错误提示信息可以帮助我们了解具体...
汇川伺服电机位置控制模式参数配... 1. 基本控制参数设置 1)设置位置控制模式   2)绝对值位置线性模...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
表格中数据未显示 当表格中的数据未显示时,可能是由于以下几个原因导致的:HTML代码问题:检查表格的HTML代码是否正...
本地主机上的图像未显示 问题描述:在本地主机上显示图像时,图像未能正常显示。解决方法:以下是一些可能的解决方法,具体取决于问...
不一致的条件格式 要解决不一致的条件格式问题,可以按照以下步骤进行:确定条件格式的规则:首先,需要明确条件格式的规则是...
表格列调整大小出现问题 问题描述:表格列调整大小出现问题,无法正常调整列宽。解决方法:检查表格的布局方式是否正确。确保表格使...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...