【Go】关闭通道 用例展示

server/2024/9/20 9:18:34/ 标签: golang, 开发语言, 后端

       

目录

代码实例

关闭通道的逻辑

如何安全地关闭通道

使用 more 变量判断通道状态

结束工作的通知

通道关闭后的行为

示例一:任务分发和完成通知

示例二:生成者-消费者模式


        在 Go 语言中,close 函数用于关闭一个通道,表明没有更多的数据将被发送到这个通道。这是一个重要的操作,因为它可以帮助接收方理解发送方何时停止发送数据,从而可以安全地停止从通道接收更多数据。关闭通道后,通道中已存在的数据仍然可以被接收,但不能再向该通道发送数据。

代码实例

// _Closing_ a channel indicates that no more values
// will be sent on it. This can be useful to communicate
// completion to the channel's receivers.package mainimport "fmt"// In this example we'll use a `jobs` channel to
// communicate work to be done from the `main()` goroutine
// to a worker goroutine. When we have no more jobs for
// the worker we'll `close` the `jobs` channel.
func main() {jobs := make(chan int, 5)done := make(chan bool)// Here's the worker goroutine. It repeatedly receives// from `jobs` with `j, more := <-jobs`. In this// special 2-value form of receive, the `more` value// will be `false` if `jobs` has been `close`d and all// values in the channel have already been received.// We use this to notify on `done` when we've worked// all our jobs.go func() {for {j, more := <-jobsif more {fmt.Println("received job", j)} else {fmt.Println("received all jobs")done <- truereturn}}}()// This sends 3 jobs to the worker over the `jobs`// channel, then closes it.for j := 1; j <= 2; j++ {jobs <- jfmt.Println("sent job", j)}close(jobs)fmt.Println("sent all jobs")// We await the worker using the// [synchronization](channel-synchronization) approach// we saw earlier.<-done// Reading from a closed channel succeeds immediately,// returning the zero value of the underlying type.// The optional second return value is `true` if the// value received was delivered by a successful send// operation to the channel, or `false` if it was a// zero value generated because the channel is closed// and empty._, ok := <-jobsfmt.Println("received more jobs:", ok)
}

关闭通道的逻辑

  jobs 通道用来从 main 协程向工作协程发送工作任务。当所有的工作都发送完毕后,通过 close(jobs) 来关闭 jobs 通道,表示没有更多的工作会被发送。

如何安全地关闭通道

        关闭通道应当由发送方执行,且只能执行一次。如果多次关闭同一个通道,或者在通道已关闭后再发送数据,程序将引发运行时恐慌(panic)。因此,确保关闭通道的操作只在确信所有数据发送完毕后执行,并且由单一的发送方协程来处理,是非常重要的。

使用 more 变量判断通道状态

        代码中工作协程使用 for 循环通过 j, more := <-jobsjobs 通道接收数据。这里的 more 是一个布尔值,如果能从通道接收到数据,moretrue;如果通道被关闭并且所有数据都已经接收完毕,more 则为 false。这允许工作协程知道何时停止等待新的工作,因为它通过 more 的状态了解到通道已经关闭。

结束工作的通知

        当 more 变量为 false 时,工作协程通过发送 truedone 通道来通知 main 协程所有的工作都已经处理完毕,随后返回结束自身的执行。

通道关闭后的行为

        关闭通道后,尝试从通道接收仍然是可能的。如果通道中仍有未被接收的数据,这些数据仍然可以被接收。一旦所有数据都被接收,任何进一步的接收尝试都会立即返回通道元素类型的零值,more 变量将返回 false,表明没有更多的数据。

        通过这种机制,Go 语言的通道和协程间同步为并发编程提供了强大而安全的工具。练习和理解如何正确使用通道和协程,对于开发高效、健壮的并发程序至关重要。

示例一:任务分发和完成通知

        在 Go 语言中,关闭通道的使用场景非常多,它是协程间通信过程中一个重要的同步手段。下面我将提供两个实用的例子,展示在不同场景下如何正确地使用关闭通道的功能。

        在这个例子中,我们将使用一个通道来分发任务给多个工作协程,并在所有任务完成后进行通知。

package mainimport ("fmt""sync"
)func worker(id int, jobs <-chan int, wg *sync.WaitGroup) {for j := range jobs {fmt.Printf("Worker %d processing job %d\n", id, j)wg.Done()}fmt.Printf("Worker %d finished all jobs\n", id)
}func main() {const numJobs = 5jobs := make(chan int, numJobs)var wg sync.WaitGroup// 创建3个工作协程for w := 1; w <= 3; w++ {go worker(w, jobs, &wg)}// 发布任务for j := 1; j <= numJobs; j++ {jobs <- jwg.Add(1)}close(jobs) // 发布完任务后关闭通道wg.Wait() // 等待所有任务完成fmt.Println("All jobs are completed")
}

        在这个例子中,我们创建了一个jobs通道分发任务给工作协程,并使用sync.WaitGroup来等待所有任务完成。通道被关闭来告知工作协程不会有新的任务发送。

示例二:生成者-消费者模式

        我们将展示一个基础的生成者-消费者模式,其中生成者协程产生数据,消费者协程处理数据。

package mainimport ("fmt""time"
)func producer(ch chan<- int) {for i := 0; i < 10; i++ {fmt.Printf("Produced: %d\n", i)ch <- itime.Sleep(time.Second) // 模拟耗时的生产过程}close(ch) // 生产完毕,关闭通道
}func consumer(ch <-chan int) {for i := range ch {fmt.Printf("Consumed: %d\n", i)}fmt.Println("All items have been consumed.")
}func main() {ch := make(chan int)go producer(ch) // 启动生产者协程consumer(ch)    // 在主协程中消费数据
}

        在这个例子中,producer 协程负责生产数据并发送到通道 ch 中。当所有数据生产完毕后,它关闭了通道。consumer 函数通过从通道接收数据来消费它,一旦通道关闭,for 循环就会结束。


http://www.ppmy.cn/server/23391.html

相关文章

c++11新增数组 -- array

概述: array是c11新增的静态数组类型&#xff0c;数组我们平时使用的很多&#xff0c;那为什么在c11增加一个array静态数组的类呢? array的提出可以完全代替我们平时使用的数组&#xff0c;而且其具有更高的安全性&#xff0c;而且使用array表示数组&#xff0c;我们不需要在使…

第30篇 RPC概述

RPC&#xff08;Remote Procedure Call&#xff0c;远程过程调用&#xff09;是一种编程技术&#xff0c;使得开发者能够像调用本地函数一样调用位于不同进程、不同主机上的函数或服务。这种技术隐藏了底层网络通信细节&#xff0c;使得分布式系统中的组件能够无缝协作&#xf…

MATLAB使用贝叶斯网络bnt工具箱:使用手册详解

MATLAB构建贝叶斯网络bnt工具箱: 贝叶斯网络(Bayesian networks)相关网页资源介绍1 工具包安装2 创建贝叶斯网络2.1 图结构(Graph structure)2.2 创建贝叶斯网络外壳(Creating the Bayes net shell)2.3 创建贝叶斯网络2.3 参数2.4 随机参数2 推断(Inference)2.1 边缘分…

SpringMVC架构中Controller层调用的service接口而非实现类serviceImpl的原因及实现原理

为什么Controller层调用的是service接口&#xff0c;而不是其实现类&#xff1f; 在Java的MVC架构中&#xff0c;通常Controller层注入的是服务层的接口&#xff0c;而不是实现类。这样做的原因主要是为了实现面向接口编程和依赖注入&#xff0c;有助于降低各层之间的耦合性&a…

力扣HOT100 - 207. 课程表

解题思路&#xff1a; class Solution {public boolean canFinish(int numCourses, int[][] prerequisites) {int[] inDegree new int[numCourses];//存每个结点的入度List<List<Integer>> res new ArrayList<>();//存结点之间依赖关系Queue<Integer>…

.NET 高级开发人员面试常见问题及解答

当面试.NET高级开发人员时&#xff0c;面试官通常会围绕技术深度、问题解决能力、项目经验以及编程理念等方面提出问题。以下是20个常见的面试问题及其详细解答&#xff1a; 问题&#xff1a;请简述ASP.NET MVC的工作原理&#xff1f; 解答&#xff1a;ASP.NET MVC是一个基于MV…

clickhouse学习笔记05

ClickHouseSpringBoot2.XMybatisPlus整合搭建 添加需要的依赖&#xff1a; 添加clickhouse依赖&#xff1a; 配置数据库配置&#xff1a; 我们框架就搭建完了。 ClickHouse的项目案例统计需求讲解 ClickHouse的项目案例统计库表和数据准备 添加数据&#xff1a; 数据都插入进来…

安卓常用组件(启停活动页面、活动之间传递信息、收发应用广播、操作后台服务)

启停活动页面 Activity的启动和结束 页面跳转可以使用startActivity接口&#xff0c;具体格式为startActivity(new Intent(this, 目标页面.class));。 关闭一个页面可以直接调用finish();方法即可退出页面。 Activity的生命周期 页面在安卓有个新的名字叫活动&#xff0c;因…

Linux系统安全与应用【一】

目录 1.账号安全控制 1.1 系统账号清理 1.2 密码安全控制 1.3 命令历史限制 1.4 命令总结 2.系统引导和登录控制 2.1 使用su命令切换用户 2.2 限制使用su命令的用户 3.可插拔式认证模块PAM 3.1 linux中的PAM安全认证 3.2 PAM认证原理​编辑 3.3 PAM认证的构成 3.4 P…

微服务使用SockJs+Stomp实现Websocket 前后端实例 | Vuex形式断开重连、跨域等等问题踩坑(二)

大家好&#xff0c;我是程序员大猩猩。 上次我们实践了&#xff0c;Java后端如何完成SockJSStomp的配置实现。 微服务使用SockJsStomp实现Websocket 前后端实例 | Vuex形式断开重连、跨域等等问题踩坑&#xff08;一&#xff09; 那么今天我们做一下web vue端的是如何来实现…

Stable Diffusion 模型分享:Inkpunk Diffusion(动漫、墨水朋克)

本文收录于《AI绘画从入门到精通》专栏&#xff0c;专栏总目录&#xff1a;点这里&#xff0c;订阅后可阅读专栏内所有文章。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八 下载地址 模型介绍 在 Dreambooth 上训练的微调稳定扩散模型。隐约受…

JAVASE->数据结构|顺序表底层逻辑

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;再无B&#xff5e;U&#xff5e;G-CSDN博客 目标&#xff1a; 1. 什么是 List 2. List 常见接口介绍 3. …

标准更新丨美国发布玩具安全标准ASTM F963-23

2023年10月13日&#xff0c;美国材料试验协会 (ASTM)发布了玩具安全标准ASTM F963-23。新版标准主要修订了声响、电池可触及性、膨胀材料和弹射玩具的技术要求&#xff0c;另外&#xff0c;澄清和调整了邻苯二甲酸酯、玩具基材重金属的豁免以及溯源标签的要求&#xff0c;使其保…

17 JavaScript 学习:正则表达式

JavaScript 正则表达式 JavaScript中正则表达式是一种强大的工具&#xff0c;用于在字符串中进行模式匹配和搜索。下面是一些JavaScript中使用正则表达式的基本知识&#xff1a; 创建正则表达式&#xff1a;可以使用字面量形式或者RegExp构造函数来创建正则表达式。 字面量形式…

AHB传输---内存类型

AHB5定义了Extended_Memory_Types属性。这个属性定义了一个接口是否支持本节中描述的扩展存储器类型。如果这个属性没有定义&#xff0c;那么接口就不支持扩展存储器类型。 本规范的这一版为每类存储器类型添加了额外的HPROT信号&#xff0c;并为每种存储器类型提供了更详细的…

Visual Studio安装MFC开发组件

MFC由于比较古老了&#xff0c;Visual Studio默认没有这个开发组件。最近由于一些原因&#xff0c;需要使用这个库&#xff0c;这就需要另外安装。 参考了网上的一些资料&#xff0c;根据实际使用&#xff0c;其实很多步骤不是必须的。 https://zhuanlan.zhihu.com/p/68117276…

解析vue.config.js文件

一、用途 创建 Vue 项目时&#xff0c;默认情况下是没有 vue.config.js 文件的。Vue CLI 会提供一组默认的配置&#xff0c;用于构建和开发项目&#xff0c;这些配置在内部被封装好了&#xff0c;并不需要用户手动创建 vue.config.js 文件来进行配置。通过在项目根目录下创建 …

JAVA 每日面试题(一)

Java 面试问题及答案 1. 解释Java中的垃圾回收机制是如何工作的&#xff1f; 问题&#xff1a;在Java中&#xff0c;垃圾回收&#xff08;Garbage Collection&#xff0c;GC&#xff09;是一个自动化的过程&#xff0c;用于识别和回收不再使用的对象&#xff0c;以释放内存。…

Docker 常用命令

Docker 常用命令 镜像导出和导入重命名镜像给镜像打标签启动镜像进入容器镜像修改创建镜像 镜像导出和导入 将镜像导出到本地&#xff0c;再上传至别的服务器导入 使用 docker save 导出镜像&#xff1a; docker save -o <output_file_name>.tar <image_name>使用…

Linux抓包工具tcpdump

一、tcpdump抓包工具 1.命令格式解析 命令格式&#xff1a;tcpdump option proto dir type proto&#xff08;协议&#xff09; 1.tcp、udp、icmp 2.ip、ipv6 3.arp dir&#xff08;数据的方向 &#xff09; 1.src 192.168.7.130 只抓取源地址是7.130 2.…