深入理解Go语言中的Channel与Select

Go 语言中的 Channel 和 Select 是并发编程中的重要概念和机制,它们为协程之间的通信和同步提供了强大的支持。接下来将深入介绍 Channel 和 Select 的概念、使用方法、特性,并结合实际工作场景和示例代码进行详细讨论。

1. Channel 概述

1.1 什么是 Channel?

Channel 是 Go 语言中用于协程之间通信的管道。它允许协程之间通过发送和接收消息来进行通信,并提供了一种同步机制,用于控制协程的执行顺序。

1.2 Channel 特性
  • 类型安全:Channel 是类型安全的,只能传递指定类型的数据。
  • 阻塞操作:发送和接收操作都是阻塞的,直到发送方发送数据,或接收方接收数据为止。
  • FIFO 队列:Channel 中的数据按照先进先出(FIFO)的顺序进行处理。
  • 关闭机制:Channel 可以被关闭,关闭后不再接收新数据,但仍可以从已关闭的 Channel 中接收数据。
1.3 Channel基本使用
1.3.1 创建channel
// 创建一个用于传递整数的 Channel
ch := make(chan int)
1.3.2 发送数据到 Channel
// 向 Channel 发送数据
ch <- 10
1.3.3 从 Channel 接收数据
// 从 Channel 接收数据
data := <-ch
1.3.4 关闭 Channel
// 关闭 Channel
close(ch)
1.4Channel 应用场景
1.4.1 并发爬虫

在网络爬虫中,可以使用 Channel 来实现并发爬取网页的功能。下面是一个简化的示例代码:

package mainimport ("fmt""net/http"
)func crawl(url string, ch chan<- string) {resp, err := http.Get(url)if err != nil {fmt.Println("Error:", err)return}defer resp.Body.Close()ch <- url
}func main() {urls := []string{"http://example.com", "http://example.org", "http://example.net"}ch := make(chan string)for _, url := range urls {go crawl(url, ch)}for i := 0; i < len(urls); i++ {fmt.Println(<-ch)}
}

在这个示例中,我们创建了一个 Channel ch 用于存储爬取到的网页 URL。然后并发地启动了多个爬虫协程,每个协程负责爬取一个网页,并将其 URL 发送到 Channel 中。最后,主协程从 Channel 中接收 URL 并打印出来。

1.4.2 工作池模式

工作池模式是一种常见的并发编程模式,可以用于控制并发任务的数量。下面是一个简单的工作池示例:

package mainimport ("fmt""sync"
)func worker(id int, jobs <-chan int, results chan<- int) {for job := range jobs {fmt.Printf("Worker %d started job %d\n", id, job)results <- job * 2fmt.Printf("Worker %d finished job %d\n", id, job)}
}func main() {const numJobs = 5jobs := make(chan int, numJobs)results := make(chan int, numJobs)var wg sync.WaitGroup// 启动多个工作者for i := 1; i <= 3; i++ {wg.Add(1)go func(workerID int) {defer wg.Done()worker(workerID, jobs, results)}(i)}// 提供工作for j := 1; j <= numJobs; j++ {jobs <- j}close(jobs)// 收集结果go func() {wg.Wait()close(results)}()// 打印结果for result := range results {fmt.Println("Result:", result)}
}

在这个示例中,我们创建了一个固定大小的工作池,并启动了多个工作者协程。然后,向工作池中发送一定数量的任务,并等待所有任务完成后,关闭结果 Channel 并打印结果。

2. Select 语句

2.1 什么是 Select?

Select 是 Go 语言中的一个控制结构,用于处理多个 Channel 上的操作。它类似于 switch 语句,但是用于 Channel 的接收操作。

2.2 Select 语法
select {
case data := <-ch1:fmt.Println("Received from ch1:", data)
case data := <-ch2:fmt.Println("Received from ch2:", data)
}

Select 语句用于在多个 Channel 上等待数据,并执行相应的操作。当有多个 Channel 同时就绪时,Select 会随机选择一个执行。

3. Channel 与 Select 的结合应用

3.1 多路复用
func main() {ch1 := make(chan int)ch2 := make(chan string)go func() {ch1 <- 1}()go func() {ch2 <- "hello"}()select {case data := <-ch1:fmt.Println("Received from ch1:", data)case data := <-ch2:fmt.Println("Received from ch2:", data)}
}

在这个示例中,我们创建了两个 Channel ch1ch2,并分别向其发送了数据。然后使用 Select 语句等待这两个 Channel 上的数据,并执行相应的操作。由于 Select 会随机选择一个就绪的 Channel,因此无论哪个 Channel 先就绪,都会打印出相应的数据。

3.2 超时处理
func main() {ch := make(chan int)timeout := time.After(1 * time.Second)select {case data := <-ch:fmt.Println("Received:", data)case <-timeout:fmt.Println("Timeout")}
}

在这个示例中,我们创建了一个 Channel ch 和一个 1 秒的超时时间。然后使用 Select 语句等待 Channel 上的数据,并设置了超时处理,当超过指定时间后,会执行相应的超时操作。

4. Channel 和 Select 的最佳实践

4.1 优雅的退出
func worker(ch <-chan bool) {for {select {case <-ch:fmt.Println("Worker exiting...")returndefault:// 执行任务...}}
}

在并发任务中,我们通常需要实现优雅的退出机制。可以通过在 Channel 上发送信号来通知协程退出,并在协程中使用 Select 来监听退出信号,实现优雅退出。

4.2 限流控制
func worker(ch <-chan int, semaphore chan struct{}) {for {select {case <-semaphore:data := <-chfmt.Println("Received:", data)}}
}

在高并发场景中,为了避免资源耗尽和性能下降,可以使用 Channel 和 Select 结合控制并发数量,实现限流控制。

5. 总结

Channel 和 Select 是 Go 语言中非常强大和灵活的并发编程工具,它们为协程之间的通信和同步提供了强大的支持。通过结合 Channel 和 Select 的使用,我们可以实现各种复杂的并发模式,如多路复用、超时处理、优雅退出和限流控制等。希望以上内容能够对大家加深对 Channel 和 Select 的理解,并能够在实际工作中发挥作用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1113264.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

处理器管理补充——线程

传送门&#xff1a;操作系统——处理器管理http://t.csdnimg.cn/avaDO 1.1 线程的概念 回忆&#xff1a;[未引入线程前] 进程有两个基本属性&#xff1a;拥有资源的独立单位、处理器调度和分配的基本单位。 引入线程以后&#xff0c;线程将作为处理器调度和运行的基本单位&…

Android T 远程动画显示流程其二——动画的添加流程(更新中)

前言 接着上篇文章分析 Android T 远程动画显示流程其一 切入点——处理应用的显示过渡 下面&#xff0c;我们以从桌面点击一个应用启动的场景来分析远程动画的流程&#xff0c;窗口添加的流程见Android T WMS窗口相关流程 这里我们从AppTransitionController.handleAppTran…

【Python爬虫】requests库get和post方法使用

requests库是一个常用于http请求的模块&#xff0c;性质是和urllib&#xff0c;urllib2是一样的&#xff0c;作用就是向指定目标网站的后台服务器发起请求&#xff0c;并接收服务器返回的响应内容。 1. 安装requests库 使用pip install requests安装 如果再使用pip安装python…

书生·浦语大模型实战营第二节课作业

使用 InternLM-Chat-7B 模型生成 300 字的小故事&#xff08;基础作业1&#xff09;。 熟悉 hugging face 下载功能&#xff0c;使用 huggingface_hub python 包&#xff0c;下载 InternLM-20B 的 config.json 文件到本地&#xff08;基础作业2&#xff09;。 下载过程 进阶…

YOLOv5代码解读[02] models/yolov5l.yaml文件解析

文章目录 YOLOv5代码解读[02] models/yolov5l.yaml文件解析yolov5l.yaml文件检测头1--->耦合头检测头2--->解耦头检测头3--->ASFF检测头Model类解析parse_model函数 YOLOv5代码解读[02] models/yolov5l.yaml文件解析 yolov5l.yaml文件 # YOLOv5 &#x1f680; by Ult…

maven 打包命令

Maven是基于项目对象模型(POM project object model)&#xff0c;可以通过一小段描述信息&#xff08;配置&#xff09;来管理项目的构建&#xff0c;报告和文档的软件项目管理工具。 Maven的核心功能便是合理叙述项目间的依赖关系&#xff0c;通俗点讲&#xff0c;就是通过po…

python 3D散点图

from mpl_toolkits import mplot3d import numpy as np import matplotlib.pyplot as plt#解决中文乱码和负号不显示问题 plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False fig plt.figure() ax plt.axes(projection3d)#构造3个散点向量x1[[…

数据结构 计算结构体大小

一、规则&#xff1a; 操作系统制定对齐量&#xff1a; 64位操作系统&#xff0c;默认8Byte对齐 32位操作系统&#xff0c;默认4Byte对齐 结构体对齐规则&#xff1a; 1.结构体整体的大小&#xff0c;需要是最大成员对齐量的整数倍 2.结构体中每一个成员的偏移量需要存在…

MKdocs添加顶部公告栏

效果如图&#xff1a; docs/overrides下新建main.html &#xff0c;针对main.html文件 树状结构如下: $ tree -a . ├── .github │ ├── .DS_Store │ └── workflows │ └── PublishMySite.yml ├── docs │ └── index.md │ └──overrides │…

vulfocus靶场搭建

vulfocus靶场搭建 什么是vulfocus搭建教程靶场配置场景靶场编排靶场优化 什么是vulfocus Vulfocus 是一个漏洞集成平台&#xff0c;将漏洞环境 docker 镜像&#xff0c;放入即可使用&#xff0c;开箱即用&#xff0c;我们可以通过搭建该靶场&#xff0c;简单方便地复现一些框架…

基于Jenkins实现的CI/CD方案

基于Jenkins实现的CI/CD方案 前言 最近基于Jenkins的基座&#xff0c;搭建了一套适用于我们项目小组的持续集成环境。现在把流程整理分享出来&#xff0c;希望可以给大家提供一些帮助和思路。 使用到的组件和版本 组件名称组件版本作用Harbor2.7.3镜像仓库Jenkins2.319.2持…

消息队列-RabbitMQ:死信队列

十五、死信队列 1、死信的概念 先从概念解释上搞清楚这个定义&#xff0c;死信&#xff0c;顾名思义就是无法被消费的消息&#xff0c;字面意思可以这样理解&#xff0c;一般来说&#xff0c;producer 将消息投递到 broker 或者直接到 queue 里了&#xff0c;consumer 从 que…

深入理解单端模拟多路复用器DG406DW-E3 应用于高速数据采集、ATE系统和航空电子设备解决方案

DG406DW-E3是一款16通道单端模拟多路复用器设计用于将16个输入中的一个连接到公共端口由4位二进制地址确定的输出。应用包括高速数据采集、音频信号切换和路由、ATE系统和航空电子设备。高性能低功耗损耗使其成为电池供电和电池供电的理想选择远程仪器应用。采用44V硅栅CMOS工艺…

Java实现实验室耗材管理系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 耗材档案模块2.2 耗材入库模块2.3 耗材出库模块2.4 耗材申请模块2.5 耗材审核模块 三、系统展示四、核心代码4.1 查询耗材品类4.2 查询资产出库清单4.3 资产出库4.4 查询入库单4.5 资产入库 五、免责说明 一、摘要 1.1…

05 Flink 的 WordCount

前言 本文对应于 spark 系列的 Spark 的 WordCount 这里主要是 从宏观上面来看一下 flink 这边的几个角色, 以及其调度的整个流程 一个宏观 大局上的任务的处理, 执行 基于 一个本地的 flink 集群 测试用例 /*** com.hx.test.Test01WordCount** author Jerry.X.He* ver…

HarmonyOS学习--三方库

文章目录 一、三方库获取二、常用的三方库1. UI库&#xff1a;2. 网络库&#xff1a;3. 动画库&#xff1a; 三、使用开源三方库1. 安装与卸载2. 使用 四、问题解决1. zsh: command not found: ohpm 一、三方库获取 在Gitee网站中获取 搜索OpenHarmony-TPC仓库&#xff0c;在t…

MySql-DML-修改数据update

目录 修改数据 修改数据 update语法&#xff1a; update 表名 set 字段名1 值1 , 字段名2 值2 , .... [where 条件] ;案例1&#xff1a;将tb_emp表中id为1的员工&#xff0c;姓名name字段更新为’张三’ update tb_emp set name张三,update_timenow() where id1;案例2&…

js设计模式:状态模式

作用: 将对象的行为和状态进行分离,状态是由行为操作决定的,而不是直接控制。 同时,行为也是由状态决定的,每个状态都有自己的行为和相应的方法 行为与状态分离,可以使代码方便维护 示例: <!DOCTYPE html> <html lang"en"><head><meta cha…

CogFixtureTool(坐标系、校正与定位)

坐标系 任何VisionPro图像都支持一组坐标空间&#xff0c;为表达特定特征的位置提供数字框架。最有用的空间是根空间和用户空间&#xff0c;根空间将点与原始获取图像中的像素相关联&#xff0c;用户空间用于获得校准和固定空间中的特征位置和测量值。 根空间 图像的根空间…

机器学习——正规方程

正规方程的基本介绍 之前我们使用梯度下降算法求代价函数J(θ)的最小值&#xff0c;而梯度下降算法是通过一步步不断地迭代来收敛到全局最小值&#xff0c;如下 而正规方程则是另一种求解J(θ)最小值的方法&#xff0c;并且正规方程不需要通过迭代&#xff0c;而是一次性得到θ…