【Go】通道:缓冲通道和非缓冲通道
目录
通道的基本概念
缓冲通道
非缓冲通道
总结
通道的基本概念
在Go语言中,通道是一种特殊的类型,用于在goroutine之间传递数据。你可以将通道想象为数据的传输管道。通道分为两种类型:
- 非缓冲通道(Unbuffered Channels):发送操作会阻塞,直到另一goroutine在对应的通道上执行接收操作,这时候数据才会被发送成功,发送goroutine才能继续执行。
- 缓冲通道(Buffered Channels):可以存储一定数量的值,无需立即有goroutine接收这些值。
缓冲通道
缓冲通道通过在make
函数中指定第二个参数来创建,这个参数定义了通道可以存储的值的数量。在你提供的代码中,messages
是一个缓冲通道,其容量为2:
messages := make(chan string, 2)
这意味着即使没有goroutine准备好接收数据,你也可以往messages
通道发送两个字符串。如果尝试发送更多的数据,那么发送操作会阻塞,直到有空间可用。
messages <- "buffered"
messages <- "channel"fmt.Println(<-messages)
fmt.Println(<-messages)
简单代码:
package mainimport "fmt"func main() {// Here we `make` a channel of strings buffering up to// 2 values.messages := make(chan string, 2)// Because this channel is buffered, we can send these// values into the channel without a corresponding// concurrent receive.messages <- "buffered"messages <- "channel"// Later we can receive these two values as usual.fmt.Println(<-messages)fmt.Println(<-messages)
}
使用场景
缓冲通道在需要解耦发送者和接收者的速率时非常有用。例如,在一个情况下,可能生产者生成数据的速度快于消费者处理数据的速度,那么一个适当大小的缓冲可以帮助平衡这种速率差异,减少直接阻塞的发生。
这里将展示一个使用缓冲通道的Go程序,该程序模拟一个简单的并行任务处理场景,其中多个工人(goroutine)并发地从一个任务队列(缓冲通道)中获取任务并执行。此示例中,我们将创建一个任务通道和一个结果通道,每个工人都从任务通道接收任务,处理完毕后将结果发送到结果通道。这种方式非常适用于需要任务分发和结果收集的场景。
package mainimport ("fmt""time""sync"
)// Task 表示一个简单的任务,这里仅仅是一个数值
type Task int// Result 表示任务处理的结果,这里包含任务原始值和处理后的信息
type Result struct {Task TaskInfo string
}func worker(id int, tasks <-chan Task, results chan<- Result, wg *sync.WaitGroup) {defer wg.Done()for task := range tasks {fmt.Printf("工人 %d 开始处理任务 %d\n", id, task)// 模拟任务处理时间time.Sleep(time.Second)// 发送结果到结果通道results <- Result{Task: task, Info: fmt.Sprintf("工人 %d 完成", id)}}
}func main() {// 创建缓冲通道tasks := make(chan Task, 10)results := make(chan Result, 10)// 使用 WaitGroup 来等待所有工人完成var wg sync.WaitGroup// 启动三个工人 goroutinesfor i := 1; i <= 3; i++ {wg.Add(1)go worker(i, tasks, results, &wg)}// 分发任务for j := 1; j <= 5; j++ {tasks <- Task(j)}// 关闭任务通道,表示不再有任务被发送close(tasks)// 等待所有工人完成wg.Wait()// 关闭结果通道close(results)// 输出所有处理结果for result := range results {fmt.Printf("任务 %d: %s\n", result.Task, result.Info)}
}
程序说明
- 任务和结果结构:我们定义了两种类型,
Task
和Result
,分别代表任务和处理结果。 - 工人goroutine:
worker
函数是每个工人的行为定义。它持续从任务通道接收任务,处理它们(这里仅模拟为等待1秒),然后将结果发送到结果通道。 - 主函数中的并发执行:
- 创建并初始化缓冲通道
tasks
和results
。 - 启动3个工人goroutine,每个都在独立的线程中执行。
- 发送5个任务到任务通道。
- 关闭任务通道,告知工人不再有新任务。
- 使用
sync.WaitGroup
来等待所有工人的任务处理完成。 - 关闭结果通道并打印所有结果。
- 创建并初始化缓冲通道
这个例子展示了如何使用缓冲通道来管理并发任务的分配和结果收集,使得多个工人能够并行处理任务,同时主程序能够等待所有任务完成并最终收集所有的处理结果。这种模式在实际开发中非常有用,尤其是在需要并行处理大量数据或任务的应用场景中。继续努力,不断深化对Go并发编程的理解和应用!
非缓冲通道
Go语言中的非缓冲通道是一种在goroutine之间进行通信的机制,它在发送和接收数据时具有同步的特性。在非缓冲通道上,数据的发送必须有对应的接收操作同时准备好,否则发送操作会阻塞,直到有goroutine来接收数据。同样,如果通道中没有数据,接收操作也会阻塞,直到有数据被发送到通道。这种特性使得非缓冲通道不仅是数据传输的渠道,还是一个同步多个goroutine的强大工具。
基础介绍
非缓冲通道保证了数据传递的即时性,即数据发送后立即被接收。这种即时的数据交换机制意味着每个发送操作都必须有一个对应的接收操作准备接收数据,这种机制在并发编程中常用于控制不同goroutine之间的执行顺序。
下面的示例展示了如何使用非缓冲通道进行两个goroutine之间的同步通信。在这个例子中,我们将创建一个主goroutine和一个工作goroutine,主goroutine发送一个任务到工作goroutine,然后等待工作goroutine的处理结果。
package mainimport ("fmt""time"
)func worker(done chan bool) {fmt.Println("工作中...")time.Sleep(time.Second)fmt.Println("工作完成")// 发送一个值表示工作已经完成done <- true
}func main() {// 创建一个非缓冲的布尔型通道done := make(chan bool)// 启动一个工作goroutinego worker(done)// 等待工作goroutine的通知<-donefmt.Println("在主goroutine中继续执行")
}
程序解析
- 通道的创建和使用:我们通过
make(chan bool)
创建了一个非缓冲的布尔型通道done
。这个通道用来从工作goroutine向主goroutine发送任务完成的信号。 - 工作goroutine:
worker
函数模拟长时间运行的任务,完成后通过done
通道发送一个true
值来通知主goroutine任务已完成。 - 主goroutine的阻塞等待:在主goroutine中,使用
<-done
来阻塞主goroutine的执行,直到从done
通道接收到工作完成的信号。
总结
非缓冲通道是Go语言中一种实现goroutine间同步通信的强大机制。通过确保每个发送操作都必须有一个对应的接收操作同时准备好,非缓冲通道可以精确控制数据的即时传递和goroutine的执行顺序。这种通道不仅是数据传输的渠道,也是协调并发操作的关键工具。通过非缓冲通道,Go程序能够以直接且同步的方式处理并发任务,从而保持高效和可靠的执行流程。简而言之,非缓冲通道是Go并发编程中不可或缺的同步神器
缓冲通道在Go语言中是一种允许在没有接收方准备好时进行数据传输的通信机制。这种通道通过内部缓冲区来暂存数据,从而允许发送操作在缓冲区未满时立即返回,而不必等待接收方。缓冲通道的存在极大地提升了并发程序的灵活性和效率,使得goroutine之间可以更加灵活地进行非阻塞通信和数据交换。
相关文章:
【Go】通道:缓冲通道和非缓冲通道
目录 通道的基本概念 缓冲通道 非缓冲通道 总结 通道的基本概念 在Go语言中,通道是一种特殊的类型,用于在goroutine之间传递数据。你可以将通道想象为数据的传输管道。通道分为两种类型: 非缓冲通道(Unbuffered Channels&…...
Java中数组的使用
在Java编程中,数组是一种非常重要的数据结构,它允许我们存储相同类型的多个元素。对于初学者来说,理解数组的基本概念、初始化、遍历、默认值以及内存分配和使用注意事项是非常关键的。 一、数组的概念 数组是一个可以容纳多个相同类型数据…...
CAP5_Monday
A Set to Max (Easy Version) 给定数组 a 和 b,可以执行以下操作任意次 : 让 a l ∼ a r a_l\sim a_r al∼ar 中的所有所有元素变成 a i a_i ai ( l ≤ i ≤ r ) (l\leq i\leq r) (l≤i≤r), 其中 1 ≤ l ≤ r ≤ n 1\leq l \leq r \leq n 1≤…...

科大讯飞星火开源大模型iFlytekSpark-13B GPU版部署方法
星火大模型的主页:iFlytekSpark-13B: 讯飞星火开源-13B(iFlytekSpark-13B)拥有130亿参数,新一代认知大模型,一经发布,众多科研院所和高校便期待科大讯飞能够开源。 为了让大家使用的更加方便,科…...

SpringBoot基于RabbitMQ实现消息延迟队列方案
知识小科普 在此之前,简单说明下基于RabbitMQ实现延时队列的相关知识及说明下延时队列的使用场景。 延时队列使用场景 在很多的业务场景中,延时队列可以实现很多功能,此类业务中,一般上是非实时的,需要延迟处理的&a…...
Go语言使用标准库时常见错误
Go的标准库是一组增加和拓展语言的核心包。然而,很容易误用标准库,或者我们对其行为理解有限,导致产生了bug或不应该在生产级应用程序中某些功能。 1. 提供错误的持续时间 标准库提供了获取 time.Duration 的常用函数和方法,但由于 time.Duration 是 int64 的自定义类型,…...

UE5不打包启用像素流 ubuntu22.04
首先查找引擎中像素流的位置: zkzk-ubuntu2023:/media/zk/Data/Linux_Unreal_Engine_5.3.2$ sudo find ./ -name get_ps_servers.sh [sudo] zk 的密码: ./Engine/Plugins/Media/PixelStreaming/Resources/WebServers/get_ps_servers.sh然后在指定路径中…...
Redis 常用数据类型常用命令和应用场景
首先先混个眼熟 Redis 中的 8 种常用数据类型: 5 种基础数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合࿰…...

ins视频批量下载,instagram批量爬取视频信息
简介 Instagram 是目前最热门的社交媒体平台之一,拥有大量优质的视频内容。但是要逐一下载这些视频往往非常耗时。在这篇文章中,我们将介绍如何使用 Python 编写一个脚本,来实现 Instagram 视频的批量下载和信息爬取。 我们使用selenium获取目标用户的 HTML 源代码,并将其保存…...
Canvas图形编辑器-数据结构与History(undo/redo)
Canvas图形编辑器-数据结构与History(undo/redo) 这是作为 社区老给我推Canvas,于是我也学习Canvas做了个简历编辑器 的后续内容,主要是介绍了对数据结构的设计以及History能力的实现。 在线编辑: https://windrunnermax.github.io/CanvasEditor开源地…...

阿里云Centos7下编译glibc
编译glibc 原来glibc版本 编译前需要的环境: CentOS7 gcc 8.3.0 gdb 8.3.0 make 4.0 binutils 2.39 (ld -v) python 3.6.8 其他看INSTALL, 但有些版本也不易太高 wget https://mirrors.aliyun.com/gnu/glibc/glibc-2.37.tar.gz tar -zxf glibc-2.37.tar.gz cd glibc-2.37/ …...

UE5数字孪生系列笔记(四)
场景的切换 创建一个按钮的用户界面UMG 创建一个Actor,然后将此按钮UMG添加到组件Actor中 调节几个全屏的背景 运行结果 目标点切换功能制作 设置角色到这个按钮的位置效果 按钮被点击就进行跳转 多个地点的切换与旋转 将之前的目标点切换逻辑替换成旋转的逻…...

品牌故事化:Kompas.ai如何塑造深刻的品牌形象
在这个信息爆炸的时代,品牌故事化已经成为企业塑造独特形象、与消费者建立情感联系的重要手段。一个引人入胜的品牌故事不仅能够吸引消费者的注意力,还能够在消费者心中留下持久的印象,建立起强烈的情感连接。本文将深入探讨品牌故事化对于构…...
5g和2.4g频段有什么区别
运行的频段不同 2.4G和5G频段的主要区别在于它们运行的频段不同,2.4G频段运行在2.4GHz的频段上,而5G频段(这里指的是5GHz频段)运行在5GHz的频段上。12 这导致了两者在传输速度、覆盖范围、抗干扰能力等方面的明显差异。以下是详…...

交通管理在线服务系统|基于Springboot的交通管理系统设计与实现(源码+数据库+文档)
交通管理在线服务系统目录 目录 基于Springboot的交通管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户信息管理 2、驾驶证业务管理 3、机动车业务管理 4、机动车业务类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计…...
konva.js 工具类
konva.js 工具类 class KonvaCanvas {/*** 初始化画布* param {String} domId 容器dom id*/constructor(domId) {this.layer null;this.stage null;this.scale 1;this.init(domId);}/*** 聚焦到指定元素* param {String} elementId 元素dom id*/focusOn(elementId) {if (!t…...

php未能在vscode识别?
在设置里搜php,找到settings.json,设置你的安装路径即可。 成功...

解读MongoDB官方文档获取mongo7.0版本的安装步骤与基本使用
mongo式一款NOSQL数据库,用于存储非结构化数据,mongo是一种用于存储json的数据数据,可以通过mongo提供的命令解析json获取想要的值。 数据模型 了解关系数据库会很熟悉database,table,row,column的概念,分别是数据库,…...

【数据结构|C语言版】顺序表
前言1. 初步认识数据结构2. 线性表3. 顺序表3.1 顺序表的概念3.1 顺序表的分类3.2 动态顺序表的实现 结语 前言 各位小伙伴大家好!小编来给大家讲解一下数据结构中顺序表的相关知识。 1. 初步认识数据结构 【概念】数据结构是计算机存储、组织数据的⽅式。 数据…...

Unity类银河恶魔城学习记录12-17 p139 In game UI源代码
Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释,可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili UI.cs using UnityEngine;public class UI : MonoBehaviour {[SerializeFie…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...

龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...

(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...