当前位置: 首页 > news >正文

【Golang】Go语言编程思想(六):Channel,第一节,介绍Channel

Channel

下面的几个例子将会展示如何定义一个 channel:

func chanDemo() {var c chan int // chan int 的含义是, c 是一个 channel, 里面的内容是 int// 上面的声明语句将会创建一个 nil channel, c == nil, 它的作用将在 select 当// 中体现
}

创建一个非 nil 的 channel 的方法是使用内建的 make 函数:

package mainimport "fmt"func chanDemo() {c := make(chan int)go func() {		 // 由于 channel 是 goroutine 之间的通道for {		 // 因此应该建立一个 goroutine 不断收数据n := <-c // 从 channel 收数据fmt.Println(n)}}()c <- 1 // 向 channel 发数据c <- 2 // 向 channel 发数据
}func main() {chanDemo()
}

Channel 也是 Golang 当中的一等公民

在函数式编程的学习过程中,我们已经看到,函数是 Golang 的一等公民,它可以作为参数,也可以作为返回值。而 Channel 同样也是 Golang 的一等公民,它同样可以作为参数也可以作为返回值。

为了展示其用法,我们对上面的代码进行修改,首先将上面代码当中的匿名函数单独定义为一个函数:

package mainimport ("fmt""time"
)func worker(c chan int) { // channel 作为参数for {n := <-c // 从 channel 收数据fmt.Println(n)}
}func chanDemo() {c := make(chan int)go worker(c)c <- 1 // 向 channel 发数据c <- 2 // 向 channel 发数据time.Sleep(time.Second)
}func main() {chanDemo()
}

其输出仍然是 1 和 2。

为了进一步体现 channel 是一等公民,使用 var 声明一个存储 10 个 chan int 型 channel 的数组,并在循环中使用内建的 make 对每个 chan int 进行构造,并将 chan int 分发给 10 个 workers:

package mainimport ("fmt""time"
)func worker(id int, c chan int) { // channel 作为参数for {n := <-c // 从 channel 收数据fmt.Printf("Worker %d received %c\n", id, n)}
}const worker_num int = 10func chanDemo() {var channels [10]chan int // 建立一个包含 10 个 chan int 的数组 channelsfor i := range worker_num {channels[i] = make(chan int) // 使用内建的 make 构造每一个 channelgo worker(i, channels[i])    // 将 10 个 chan int 分发给 10 个 worker}for i := range worker_num {channels[i] <- 'a' + i}time.Sleep(time.Millisecond)
}func main() {chanDemo()
}

输出的结果如下,因操作设备而异:

Worker 0 received a
Worker 2 received c
Worker 1 received b
Worker 3 received d
Worker 9 received j
Worker 4 received e
Worker 5 received f
Worker 6 received g
Worker 7 received h
Worker 8 received i

channel 除了可以作为参数、可以存储在数组当中,channel 还可以作为返回值:

package mainimport ("fmt""time"
)func createWorker(id int) chan<- int {	// 返回值 chan int 用于发数据, 因此添加 <- 告知使用者// 实际上这个函数的执行相当快: 新建一个 chan int, 并开启一个由匿名函数构成的 goroutine, 之后就返回建立的 chan int// goroutine 将会一直运行下去c := make(chan int) // 在函数中创建 channel, 它也是返回值go func() {         // 开一个 goroutine, 来接受 channel 得到的内容for {n := <-c // 从 channel 收数据fmt.Printf("Worker %d received %c\n", id, n)}}()return c
}const worker_num int = 10func chanDemo() {var channels [10]chan<- int // 建立一个包含 10 个 chan int 的数组 channelsfor i := range worker_num {channels[i] = createWorker(i)}for i := range worker_num {channels[i] <- 'a' + i}for i := range worker_num {channels[i] <- 'A' + i}time.Sleep(time.Millisecond)
}func main() {chanDemo()
}

输出的结果为:

Worker 0 received a
Worker 0 received A
Worker 4 received e
Worker 9 received j
Worker 6 received g
Worker 7 received h
Worker 8 received i
Worker 2 received c
Worker 1 received b
Worker 1 received B
Worker 5 received f
Worker 3 received d
Worker 3 received D
Worker 2 received C
Worker 6 received G
Worker 4 received E
Worker 5 received F
Worker 7 received H
Worker 8 received I
Worker 9 received J

bufferedChannel

之前我们提到过,建立一个 channel 之后,如果向 channel 当中写入数据,则应该有一个 goroutine 负责接收数据(即,在 go func 的函数体内进行 n := <- channel)。

比如,运行下述代码:

func bufferedChannel() {c := make(chan int)c <- 1
}func main() {bufferedChannel()
}

将会产生如下的错误信息:
在这里插入图片描述
可以为 channel 加入一个缓冲区,来解决上述问题:

func bufferedChannel() {c := make(chan int, 3) // 在 make 当中进一步输入参数 3, 代表当前缓冲区的大小设置为 3c <- 1c <- 2c <- 3
}func main() {bufferedChannel()
}

此时程序可以正常运行,不会 deadlock,如果进一步发送 4,才会 deadlock。

现在输出 channel 当中的数据:

func worker(id int, c chan int) {for {n := <-c // 从 channel 收数据fmt.Printf("Worker %d received %d\n", id, n)}
}func bufferedChannel() {c := make(chan int, 3) // 在 make 当中进一步输入参数 3, 代表当前缓冲区的大小设置为 3go worker(0, c)c <- 1c <- 2c <- 3c <- 4time.Sleep(time.Millisecond)
}func main() {bufferedChannel()
}

输出的结果为:

Worker 0 received 1
Worker 0 received 2
Worker 0 received 3
Worker 0 received 4

我们还想要知道,什么时候 channel 当中的数据发完了。应该由发送方来通知接收方,没有新的数据要发送了:

func channelClose() {c := make(chan int)go worker(0, c)c <- 1c <- 2c <- 3c <- 4close(c) // 告诉接受方, 数据发完了time.Sleep(time.Millisecond)
}func main() {channelClose()
}

输出的结果如下:

Worker 0 received 1
Worker 0 received 2
Worker 0 received 3
Worker 0 received 4
Worker 0 received 0
Worker 0 received 0
Worker 0 received 0
Worker 0 received 0
Worker 0 received 0
Worker 0 received 0
Worker 0 received 0
Worker 0 received 0
Worker 0 received 0
Worker 0 received 0
... (Worker 0 received 0 repeated ...)

当 channel 通过 close 通知 goroutine 没有数据要发送了的时候,goroutine 仍然会接收数据,只不过接受的数据是零值。在 goroutine 接收 channel 的数据时,可以使用两个返回值 n 和 ok 来判断 channel 是否 close,因此我们对 worker 进行修改:

func worker(id int, c chan int) {for {n, ok := <-c // 使用两个值来判断 channel 是否 closeif !ok {break}fmt.Printf("Worker %d received %d\n", id, n)}
}

此时的输出为:

Worker 0 received 1
Worker 0 received 2
Worker 0 received 3
Worker 0 received 4

另一种判断 channel 是否 close 的方式是在 for 循环使用:

func worker(id int, c chan int) {for n := range c {fmt.Printf("Worker %d received %d\n", id, n)}
}

可以得到相同的结果。

总结上述学习到的内容:

  • 本节介绍了 channel 及其定义、发送、接收数据的方法;
  • 如何定义以及使用 bufferd channel,在 make 内置方法构造 channel 时显式地指定 buffer 的大小即可;
  • 在接收数据时使用 range 可以方便地判断 channel 是否关闭。

为什么使用 Channel?原因是:不要通过共享内存来通信,而是通过通信来共享内存。

通过共享内存来通信的典型例子是,两个线程之间通过一个 flag 变量来判断事务是否完成。

相关文章:

【Golang】Go语言编程思想(六):Channel,第一节,介绍Channel

Channel 下面的几个例子将会展示如何定义一个 channel&#xff1a; func chanDemo() {var c chan int // chan int 的含义是, c 是一个 channel, 里面的内容是 int// 上面的声明语句将会创建一个 nil channel, c nil, 它的作用将在 select 当// 中体现 }创建一个非 nil 的 c…...

【Flux.jl】 卷积神经网络

Flux.jl 是包含卷积神经网络的, 但是官方API文件中没有给出一个完整的程序框架, 只是对所需神经元给了局部解释, 此外对 model-zoo 模型动物园中的案例没有及时跟着 Flux.jl 的版本更新, 也无法运行出来结果。 因此本文搭建了一个完整可训练的卷积神经网络。 Conv 卷积算子…...

大模型在辅导场景的深度应用,猿辅导素养课推出启发性“AI作文通”

猿辅导集团旗下的飞象星球面向学校发布“飞象AI作文”&#xff0c;让教育大模型成为老师的AI批改助手、学生的写作助手。芥末堆注意到&#xff0c;猿辅导集团旗下的猿辅导素养课也推出了名为“AI作文通”的AI作文功能&#xff0c;已于7月正式大规模上线&#xff0c;在AI教育领域…...

深入了解架构中常见的4种缓存模式及其实现

4种缓存模式 随着应用程序的复杂性日益增加&#xff0c;缓存管理变得至关重要。缓存不仅能有效减轻数据库负载&#xff0c;还能显著提升数据访问速度。选择合适的缓存模式能够在不同的业务场景下发挥出最佳效果。 本文将详细介绍四种常见的缓存模式&#xff1a;Cache-Aside (…...

Hermes engine on React Native 0.72.5,function无法toString转成字符串

问题描述 Hermes engine on React Native 0.72.5&#xff0c;function无法toString转成字符串 环境 npm6.14.18 node16.17.1项目依赖 "react": "18.2.0", "react-dom": "18.2.0", "react-native": "0.72.5", …...

Spring Boot + MySQL 多线程查询与联表查询性能对比分析

Spring Boot MySQL: 多线程查询与联表查询性能对比分析 背景 在现代 Web 应用开发中&#xff0c;数据库性能是影响系统响应时间和用户体验的关键因素之一。随着业务需求的不断增长&#xff0c;单表查询和联表查询的效率问题日益凸显。特别是在 Spring Boot 项目中&#xff0…...

Java 设计模式~工厂模式

在java开发&#xff0c;工厂模式应用场景有哪些&#xff1f;在Spring boot原码中 有哪些工厂类&#xff0c;并做相应的代码介绍。 工厂模式 工厂模式&#xff08;Factory Pattern&#xff09;是Java中一种常用的创建型设计模式&#xff0c;它提供了一种创建对象的最佳方式。此…...

OmicsTools生信环境全自动化安装配置教程,代做生信分析和辅导

OmicsTools软件介绍和下载安装配置 软件介绍 我开发了一款本地电脑无限使用的零代码生信数据分析作软图神器电脑软件OmicsTools&#xff0c;旨在成为可以做各种医学生物生信领域科研数据分析作图的的全能科研软件&#xff0c;欢迎大家使用OmicsTools进行生物医学科研数据分析…...

鸿蒙HarmonyOS应用开发 探索 HarmonyOS Next-从开发到实战掌握 HarmonyOS Next 的分布式能力

鸿蒙心路旅程&#xff1a;探索 HarmonyOS Next-从开发到实战掌握 HarmonyOS Next 的分布式能力 HarmonyOS Next 是华为推出的全新一代操作系统&#xff0c;旨在进一步推动分布式技术的深度应用和生态融合。本文将从技术特点、应用场景入手&#xff0c;通过实战案例与代码示例&…...

二分模板题

题目传送门 主要思路&#xff1a; 暴力会tle n的3次方了然后 二分可以找中间然后去二分枚举两边 最后结果 ansa小于它的数*c大于它的数 注意要判断是否符合条件 即如果a的小于它的数还大于它就不成立 或者c的数小于它也不成立结果 要注意转long long ans(long long)tp1*tp2; …...

一篇文章掌握Git的基本原理与使用

目录 一、创建仓库 1.1 git init 1.2 git clone 二、工作区域与文件状态 三、添加和提交文件 3.1 git status 3.2 git add git rm --cached 3.3 git commit git log 四、版本回退 soft hard mixed 总结 五、查看差异 工作区与暂存区 工作区与本地仓库 暂存区…...

「Mac畅玩鸿蒙与硬件43」UI互动应用篇20 - 闪烁按钮效果

本篇将带你实现一个带有闪烁动画的按钮交互效果。通过动态改变按钮颜色&#xff0c;用户可以在视觉上感受到按钮的闪烁效果&#xff0c;提升界面互动体验。 关键词 UI互动应用闪烁动画动态按钮状态管理用户交互 一、功能说明 闪烁按钮效果应用实现了一个动态交互功能&#xf…...

朗新科技集团如何用云消息队列 RocketMQ 版“快、准、狠”破解业务难题?

作者&#xff1a;邹星宇、刘尧 朗新科技集团&#xff1a;让数字化的世界更美好 朗新科技集团股份有限公司是领先的能源科技企业&#xff0c;长期深耕电力能源领域&#xff0c;通过新一代数字化、人工智能、物联网、电力电子技术等新质生产力&#xff0c;服务城市、产业、生活中…...

【Ubuntu】Ubuntu的Desktop(学习/用户使用)和Bit版本(工作)

这篇文章似乎没什么必要写&#xff0c;但想了想还是决定记录一下&#xff0c;也许对新手入坑Ubuntu会有帮助&#xff0c; 事实上也很简单&#xff0c;一个是桌面版本&#xff0c;另一个是字符界面版本。 桌面版&#xff1a;拥有图形桌面 字符界面&#xff0c;易上手&#xff…...

cmake CMAKE_CURRENT_SOURCE_DIR和CMAKE_CURRENT_LIST_DIR的区别

在 CMake 中&#xff0c;CMAKE_CURRENT_LIST_DIR 和 CMAKE_CURRENT_SOURCE_DIR 都是指代当前 CMake 文件所在的路径&#xff0c;但它们的含义和用途有所不同&#xff1a; CMAKE_CURRENT_LIST_DIR&#xff1a; 表示 当前处理的 CMake 文件&#xff08;例如 CMakeLists.txt&#…...

学会用VSCode debug

本文主要介绍了 VS Code 的调试功能&#xff0c;包括其强大的内置调试器&#xff0c;支持多种语言&#xff0c;如 JavaScript、TypeScript 等。通过简单项目示例展示调试过程&#xff0c;还介绍了运行面板和菜单、启动配置、调试操作、断点、记录点等功能&#xff0c;以及三种调…...

C语言专题之结构体的使用

结构体&#xff08;struct&#xff09;是一种用户自定义的数据类型&#xff0c;它允许将不同类型的数据组合在一起&#xff0c;形成一个新的数据类型。结构体在编程中非常常见&#xff0c;尤其是在需要处理复杂数据结构的情况下。以下是结构体的基本使用方法&#xff1a; 一、结…...

python中的高阶函数

1、什么是高阶函数&#xff1f; 高阶函数是指将函数作为参数传入。就是高阶函数 2、高阶函数有哪些&#xff1f; map 映射函数 >>> print(list(map(lambda x:x*x,range(1,11)))) [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] >>> print(list(map(lambda x:st…...

学习笔记063——通过使用 aspose-words 将 Word 转 PDF 时,遇到的字体改变以及乱码问题

文章目录 1、问题描述&#xff1a;2、解决方法&#xff1a; 1、问题描述&#xff1a; Java项目中&#xff0c;有个需要将word转pdf的需求。本人通过使用aspose-words来转换的。在Windows中&#xff0c;转换是完全正常的。但是当部署到服务器时&#xff0c;会出现转换生成的pdf…...

SpringBoot整合Mockito进行单元测试超全详细教程 JUnit断言 Mockito 单元测试

Mock概念 Mock叫做模拟对象&#xff0c;即用来模拟未被实现的对象可以预先定义这个对象在特定调用时的行为&#xff08;例如返回值或抛出异常&#xff09;&#xff0c;从而模拟不同的系统状态。 导入Mock依赖 pom文件中引入springboot测试依赖&#xff0c;spring-boot-start…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象&#xff0c;只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意&#xff1a;它移动的位置必须是相连的有内容的单元格…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...