极简的go语言channel入门

2024-09-03 10:28
文章标签 语言 go 入门 channel 极简

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

写在文章开头

很久没写go语言相关的文章了,近期准备整理整理go语言channel相关的知识点,而本文将通过几个示例快速带读者了解channel的基本概念,希望对你有帮助。

在这里插入图片描述

Hi,我是 sharkChili ,是个不断在硬核技术上作死的 java coder ,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili

因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

在这里插入图片描述

快速入门go语言channel基本概念

channel基础使用示例

作为一个java开发,笔者经常将channel的概念和阻塞队列进行关联,只不过两者在细节和理念上有些许区别,这里笔者先给出一个channel的基础示例,我们会往一个长度为1的channel中投递数据,然后从channel中取出数据并打印:

在这里插入图片描述

对应的代码如下所示,最终输出结果为:2024/08/31 10:07:22 receive data from the channel: hello world:

func main() {//声明一个channel,长度为1ch := make(chan string, 1)//往channel中投递数据ch <- "hello world"//取出channel数据s := <-ch//输出结果log.Println("receive data from the channel:", s)}

channel基础语法介绍

这里通过一个简单的示例了解的channel的使用,基于此示例我们进行一下语法拓展,如上所示,本质上channel的创建语法有两种:
第一种是make(chan type)这种就是所谓的无缓冲channel,这意味着投递到channel没有任何缓冲区,数据必须被即使处理掉才能投递新新数据:

在这里插入图片描述

对此我们再给出上一个代码的示例进行改造,将size去掉,这就是无缓冲channel的声明示例,运行时抛出了 all goroutines are asleep - deadlock!,很明显,因为无缓冲区的原因导致投递到channel的数据必须即使被消费,导致当前协程投递之后就无法往后走进而休眠,最终导致了死锁:

func main() {//声明一个无缓冲区channelch := make(chan string)//往channel中投递数据ch <- "hello world"//取出channel数据s := <-ch//输出结果log.Println("receive data from the channel:", s)}

channel的第二种语法就是我们最开始示例的有缓冲区channel,对应语法为make(chan type, size),需要注意的是如果size设置为0,那么channel仍然是个无缓冲区channel
接下来再说说channel数据的存取语法,如上文代码示例所示,对于存取go语言统一使用"<-",符号的左边即箭头所指向的就是消费者,右边是生产者,例如我们要往channel中投递数据,那么channel就是消费者,而我们的业务就是生产者,对应格式为:

channel<-data

相反,如果我们希望从channel中读取数据,那么我们的协程就是消费者,而channel就是生产者,那么语法就是反过来:

data<-channel

最后再说明一个特殊情况,其实go语言是支持丢弃channel数据的,还是以上述逻辑进行推理,因为我们要丢弃channel数据,那么channel就是生产者,因为数据要被丢弃,所以消费者为空,对应的语法为:

<-channel

channel主要解决什么问题

这里我们就来说明一下channelJava中阻塞队列不同的地方,按照go语言作者的设计理念,channel是用于解决一些并发中信号传递的,通过channel这个通信模型解耦协程间的通信,从而避免共享内存作为信号时协程竞争以及没必要的CPU资源占用。
举个共享内存的例子,我们现在有两个协程进行通信,协程1传到数字0时结束工作,按照共享内存的套路,我们会给协程1传入数字类型的指针,让协程1去轮询这个指针值的变化,直到数字变为1:

在这里插入图片描述

对此我们给出代码示例,可以看到主协程在休眠3s后修改sign的值,此时监听协程从sign的指针收到0值,由此退出循环。很明显这种做法会导致监听协程进行非必要的轮询进而消耗没必要的CPU资源,并且在高并发场景下为保证sign的并发有序,我们可能还需要通过各种互斥手段保护临界资源,这使得协程间的竞争开销变大,程序性能表现进一步降低:

func main() {//声明信号为1sign := 1//传入sign指针go listenCloseSignal(&sign)//休眠3s,修改sign的值time.Sleep(3 * time.Second)sign = 0time.Sleep(3 * time.Second)log.Println("execute over")
}func listenCloseSignal(sign *int) {for true {if *sign == 0 {log.Println("close go routine")break}}
}

取而代之我们使用channel,此时监听协程没有收到数据时就处于休眠状态,等到channel有数据才会被唤醒,又避免了非必要的空轮询开销而协程竞争开销,同时还能解耦模块间的逻辑,更有利于代码的扩展性和维护性:

func main() {ch := make(chan int)//传入sign指针go listenCloseSignal(ch)time.Sleep(3 * time.Second)ch <- 0time.Sleep(3 * time.Second)log.Println("execute over")
}func listenCloseSignal(ch chan int) {//监听channel的值sign := <-chif sign == 0 {log.Println("close go routine")}
}

而这就是设计们一直强调的:

用通道的方式共享内存,而不是共享内存进行通信

小结

自此,我们通过几个简单的案例介绍了channel的使用和注意事项,希望对你有帮助。

我是 sharkchiliCSDN Java 领域博客专家开源项目—JavaGuide contributor,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili
因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

在这里插入图片描述

这篇关于极简的go语言channel入门的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

深入理解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 初始化

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

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. 建立数据库连接二、定义模型结构体三、自动迁

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)