Go——channel

2024-06-18 17:36
文章标签 go channel

本文主要是介绍Go——channel,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

channel是Go在语言层面提供的协程间的通信方式。通过channel我们可以实现多个协程之间的通信,并对协程进行并发控制。

使用注意:

  1. 管道没有缓冲区时,从管道中读取数据会阻塞,直到有协程向管道中写入数据。类似地,向管道中写入数据会阻塞,直到有协程从管道读取数据。

  2. 管道有缓冲区时,从管道中读取数据,如果缓冲区没有数据也会进行阻塞,直到有协程向管道中写入数据。向管道写入数据,如果缓冲区已满也会进行阻塞,直到有协程从管道中读取数据。

  3. 对于一个值为nil的管道,无论读写数据都会阻塞,而且是永久阻塞。

  4. 读取已经关闭的管道,如果管道有缓冲区的话,会获取缓冲区中的数据,如果缓冲区中没有数据会返回零值

  5. 向已经关闭的管道中写入数据会触发panic【panic:send on closed channel】

  6. 读取管道的时候会返回两个值,第一个是从管道中取出元素的值,第二个是检测管道的缓冲区中是否还有元素,如果有返回true,没有返回false。

    1. 我们从一个已经关闭的管道中读取元素,如果这一个管道有缓冲区并且缓冲区中有元素,那么会获取缓冲区中的元素并true。如果这一个缓冲区没有元素,那么就会返回该管道类型的零值和false。

底层实现:

channel的底层数据结构实现源码位置:src/runtime/chan.go:hchan

type hchan struct {qcount   uint           // 当前队列中的元素个数dataqsiz uint           // 队列的长度buf      unsafe.Pointer // 指向一个数组空间,channel中的队列是通过数组实现的elemsize uint16         // 类型的大小closed   uint32         // 是否已经关闭elemtype *_type         // 管道的类型sendx    uint           // 元素写入队列中的下标位置recvx    uint           // 从环形队列中读取元素的位置recvq    waitq          // 待读取队列,阻塞中sendq    waitq          // 待写入队列,阻塞中lock     mutex          //锁,防止多个协程同时操作一个管
}

channel的底层实现由环形队列、类型信息、等待队列三部分组成。

  1. 创建管道的过程实际就是初始化hchan结构体的过程

  2. 向管道中写入数据时

    1. 如果缓冲区有空余位置,则将数据写入缓冲区,结束发送过程

    2. 如果缓冲区中没有位置,则将当前协程加入sendq队列,进入睡眠并等待被取协程唤醒。如果读取队列不为空,则会直接将数据写入到等待读取的协程中,并等待唤醒读取的协程。【先检查recvq是否为空,再检查buf是否有空位置】

  3. 从管道中读取数据

    1. 如果缓冲区有数据,则直接读取缓冲区中数据,结束读取过程

    2. 如果缓冲区中没有数据,则将当前协程加入recvq队列,进入睡眠并等待被写入协程唤醒。如果写入队列不为空,并且没有缓冲区,那么此时将直接从sendq中的第一个协程获取数据。【先检查sendq是否为空,之后根据判断,如果为空,检查环形队列中是否有数据;如果不为空,检查是否有缓冲区,如果有缓冲区将取出缓冲区中的第一个数据,并将sendq队列中的第一个协程中的数据写入到buf中,如果没有缓冲区,则直接读取sendq队列中的第一个协程】

  4. 关闭管道

      关闭管道的时候会把recvq中的协程全部唤醒,这些协程获取到的数据都为对应类型的零值。同时也会把sendq队列中的协程全部唤醒,但是这些协程会触发panic。

常见用法:

  • switch-case 随机选择一个可执行的case进行执行,如果所有的case都不能执行,则执行default,如果没有default的话,则进行阻塞等待,直到有一个可执行的case。
  • for-range 可以作用于管道,如果遍历的管道没有关闭,则会将管道中的所有的元素遍历并取出,并阻塞读取管道中的元素;如果遍历的是一个已经关闭的管道,则会取出管道中的所有的元素,并正常关闭。

这篇关于Go——channel的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1072653

相关文章

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont

Go语言编译环境设置教程

《Go语言编译环境设置教程》Go语言支持高并发(goroutine)、自动垃圾回收,编译为跨平台二进制文件,云原生兼容且社区活跃,开发便捷,内置测试与vet工具辅助检测错误,依赖模块化管理,提升开发效... 目录Go语言优势下载 Go  配置编译环境配置 GOPROXYIDE 设置(VS Code)一些基本

使用Go实现文件复制的完整流程

《使用Go实现文件复制的完整流程》本案例将实现一个实用的文件操作工具:将一个文件的内容完整复制到另一个文件中,这是文件处理中的常见任务,比如配置文件备份、日志迁移、用户上传文件转存等,文中通过代码示例... 目录案例说明涉及China编程知识点示例代码代码解析示例运行练习扩展小结案例说明我们将通过标准库 os

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

go中的时间处理过程

《go中的时间处理过程》:本文主要介绍go中的时间处理过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 获取当前时间2 获取当前时间戳3 获取当前时间的字符串格式4 相互转化4.1 时间戳转时间字符串 (int64 > string)4.2 时间字符串转时间

Go语言中make和new的区别及说明

《Go语言中make和new的区别及说明》:本文主要介绍Go语言中make和new的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 概述2 new 函数2.1 功能2.2 语法2.3 初始化案例3 make 函数3.1 功能3.2 语法3.3 初始化

Go语言中nil判断的注意事项(最新推荐)

《Go语言中nil判断的注意事项(最新推荐)》本文给大家介绍Go语言中nil判断的注意事项,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.接口变量的特殊行为2.nil的合法类型3.nil值的实用行为4.自定义类型与nil5.反射判断nil6.函数返回的

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁