极简的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

相关文章

使用SQL语言查询多个Excel表格的操作方法

《使用SQL语言查询多个Excel表格的操作方法》本文介绍了如何使用SQL语言查询多个Excel表格,通过将所有Excel表格放入一个.xlsx文件中,并使用pandas和pandasql库进行读取和... 目录如何用SQL语言查询多个Excel表格如何使用sql查询excel内容1. 简介2. 实现思路3

Go语言实现将中文转化为拼音功能

《Go语言实现将中文转化为拼音功能》这篇文章主要为大家详细介绍了Go语言中如何实现将中文转化为拼音功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 有这么一个需求:新用户入职 创建一系列账号比较麻烦,打算通过接口传入姓名进行初始化。想把姓名转化成拼音。因为有些账号即需要中文也需要英

Go语言使用Buffer实现高性能处理字节和字符

《Go语言使用Buffer实现高性能处理字节和字符》在Go中,bytes.Buffer是一个非常高效的类型,用于处理字节数据的读写操作,本文将详细介绍一下如何使用Buffer实现高性能处理字节和... 目录1. bytes.Buffer 的基本用法1.1. 创建和初始化 Buffer1.2. 使用 Writ

深入理解C语言的void*

《深入理解C语言的void*》本文主要介绍了C语言的void*,包括它的任意性、编译器对void*的类型检查以及需要显式类型转换的规则,具有一定的参考价值,感兴趣的可以了解一下... 目录一、void* 的类型任意性二、编译器对 void* 的类型检查三、需要显式类型转换占用的字节四、总结一、void* 的

Go Gorm 示例详解

《GoGorm示例详解》Gorm是一款高性能的GolangORM库,便于开发人员提高效率,本文介绍了Gorm的基本概念、数据库连接、基本操作(创建表、新增记录、查询记录、修改记录、删除记录)等,本... 目录1. 概念2. 数据库连接2.1 安装依赖2.2 连接数据库3. 数据库基本操作3.1 创建表(表关

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初

Go信号处理如何优雅地关闭你的应用

《Go信号处理如何优雅地关闭你的应用》Go中的优雅关闭机制使得在应用程序接收到终止信号时,能够进行平滑的资源清理,通过使用context来管理goroutine的生命周期,结合signal... 目录1. 什么是信号处理?2. 如何优雅地关闭 Go 应用?3. 代码实现3.1 基本的信号捕获和优雅关闭3.2

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验