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语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

Go语言中json操作的实现

《Go语言中json操作的实现》本文主要介绍了Go语言中的json操作的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录 一、jsOChina编程N 与 Go 类型对应关系️ 二、基本操作:编码与解码 三、结构体标签(Struc

使用Go调用第三方API的方法详解

《使用Go调用第三方API的方法详解》在现代应用开发中,调用第三方API是非常常见的场景,比如获取天气预报、翻译文本、发送短信等,Go作为一门高效并发的编程语言,拥有强大的标准库和丰富的第三方库,可以... 目录引言一、准备工作二、案例1:调用天气查询 API1. 注册并获取 API Key2. 代码实现3

基于Go语言开发一个 IP 归属地查询接口工具

《基于Go语言开发一个IP归属地查询接口工具》在日常开发中,IP地址归属地查询是一个常见需求,本文将带大家使用Go语言快速开发一个IP归属地查询接口服务,有需要的小伙伴可以了解下... 目录功能目标技术栈项目结构核心代码(main.go)使用方法扩展功能总结在日常开发中,IP 地址归属地查询是一个常见需求:

Kotlin 协程之Channel的概念和基本使用详解

《Kotlin协程之Channel的概念和基本使用详解》文章介绍协程在复杂场景中使用Channel进行数据传递与控制,涵盖创建参数、缓冲策略、操作方式及异常处理,适用于持续数据流、多协程协作等,需注... 目录前言launch / async 适合的场景Channel 的概念和基本使用概念Channel 的

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

Go之errors.New和fmt.Errorf 的区别小结

《Go之errors.New和fmt.Errorf的区别小结》本文主要介绍了Go之errors.New和fmt.Errorf的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考... 目录error的基本用法1. 获取错误信息2. 在条件判断中使用基本区别1.函数签名2.使用场景详细对

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

Go中select多路复用的实现示例

《Go中select多路复用的实现示例》Go的select用于多通道通信,实现多路复用,支持随机选择、超时控制及非阻塞操作,建议合理使用以避免协程泄漏和死循环,感兴趣的可以了解一下... 目录一、什么是select基本语法:二、select 使用示例示例1:监听多个通道输入三、select的特性四、使用se