【Go】通道:缓冲通道和非缓冲通道

目录

通道的基本概念

缓冲通道

非缓冲通道

总结


通道的基本概念

在Go语言中,通道是一种特殊的类型,用于在goroutine之间传递数据。你可以将通道想象为数据的传输管道。通道分为两种类型:

  1. 非缓冲通道(Unbuffered Channels):发送操作会阻塞,直到另一goroutine在对应的通道上执行接收操作,这时候数据才会被发送成功,发送goroutine才能继续执行。
  2. 缓冲通道(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)}
}

程序说明

  1. 任务和结果结构:我们定义了两种类型,TaskResult,分别代表任务和处理结果。
  2. 工人goroutineworker 函数是每个工人的行为定义。它持续从任务通道接收任务,处理它们(这里仅模拟为等待1秒),然后将结果发送到结果通道。
  3. 主函数中的并发执行
    • 创建并初始化缓冲通道 tasksresults
    • 启动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中继续执行")
}

程序解析

  1. 通道的创建和使用:我们通过make(chan bool)创建了一个非缓冲的布尔型通道done。这个通道用来从工作goroutine向主goroutine发送任务完成的信号。
  2. 工作goroutineworker函数模拟长时间运行的任务,完成后通过done通道发送一个true值来通知主goroutine任务已完成。
  3. 主goroutine的阻塞等待:在主goroutine中,使用<-done来阻塞主goroutine的执行,直到从done通道接收到工作完成的信号。

总结

        非缓冲通道是Go语言中一种实现goroutine间同步通信的强大机制。通过确保每个发送操作都必须有一个对应的接收操作同时准备好,非缓冲通道可以精确控制数据的即时传递和goroutine的执行顺序。这种通道不仅是数据传输的渠道,也是协调并发操作的关键工具。通过非缓冲通道,Go程序能够以直接且同步的方式处理并发任务,从而保持高效和可靠的执行流程。简而言之,非缓冲通道是Go并发编程中不可或缺的同步神器

        缓冲通道在Go语言中是一种允许在没有接收方准备好时进行数据传输的通信机制。这种通道通过内部缓冲区来暂存数据,从而允许发送操作在缓冲区未满时立即返回,而不必等待接收方。缓冲通道的存在极大地提升了并发程序的灵活性和效率,使得goroutine之间可以更加灵活地进行非阻塞通信和数据交换。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【御控物联】Java JSON结构转换(1):对象To对象——键值互换

文章目录 一、JSON是什么&#xff1f;二、JSON结构转换是什么&#xff1f;三、核心构件之转换映射四、案例之《JSON对象 To JSON对象》五、代码实现六、在线转换工具七、技术资料 一、JSON是什么&#xff1f; Json&#xff08;JavaScript Object Notation&#xff09;产生于20…

Leetcode876_链表的中间结点

1.leetcode原题链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 2.题目描述 给你单链表的头结点 head &#xff0c;请你找出并返回链表的中间结点。 如果有两个中间结点&#xff0c;则返回第二个中间结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5…

vue项目中,修改fabric默认操作

场景&#xff1a;fabricjs绘制的元素&#xff0c;默认点击鼠标左键即可自由移动元素。需要把操作改为&#xff0c;点击鼠标左键先选中元素&#xff0c;只有选中的元素&#xff0c;按住鼠标左键后才能移动 // 初始化canvas var canvas new fabric.Canvas(c);// 添加一个矩形元…

类与对象(中)

目录 赋值运算符重载 运算符重载 赋值运算符重载 前置和后置重载 日期类的实现&#xff08;前置后置也在里面&#xff09; const 成员 ​编辑 取地址及const取地址操作符重载 赋值运算符重载 运算符重载 C为了增强代码的可读性引入了运算符重载&#xff0c;运算符重载…

Android R framework修改低电量关机值为2%

问题背景 在R的系统rom产品开发中,在系统关于低电量关机的值,每个平台都不同,根据实际开发底层硬件的要求看实际情况来调整这个值,所以需要分析相关的电量变化执行的代码流程,来实现这个功能。 修改关键类 frameworks\base\services\core\java\com\android\server\Batt…

【python】python天气气候数据抓取分析可视化(源码+数据+可视化+报告)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

搜索相关知识点

记忆化搜索 记忆化搜索&#xff08;Memory search&#xff09;是一种结合了搜索和动态规划思想的算法策略。其基本思想是在搜索过程中&#xff0c;对于已经计算过的状态&#xff0c;将其结果保存下来&#xff0c;以便在后续的计算中可以直接使用&#xff0c;而不需要重新进行计…

Redis入门到通关之ZSet命令

文章目录 ⛄概述⛄常见命令有⛄RedisTemplate API❄️❄️ 向集合中插入元素&#xff0c;并设置分数❄️❄️向集合中插入多个元素,并设置分数❄️❄️按照排名先后(从小到大)打印指定区间内的元素, -1为打印全部❄️❄️获得指定元素的分数❄️❄️返回集合内的成员个数❄️❄…

汇编基础-----通过x64dbg了解什么是堆栈

汇编基础-----通过x64dbg了解什么是堆栈 什么是堆栈 在汇编语言中&#xff0c;堆栈&#xff08;stack&#xff09;是一种用于存储临时数据和执行函数调用的内存结构。堆栈是一种后进先出&#xff08;Last-In-First-Out, LIFO&#xff09;的数据结构&#xff0c;通常用于保存函…

【Docker系列】容器访问宿主机的Mysql

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

聊聊功能安全软件工具鉴定

功能安全中对于软件工具是有要求的&#xff0c;需要进行分类&#xff0c;当该工具为TCL2或者TCL3时&#xff0c;需要额外的信息支持&#xff0c;常用的方式有以下两种&#xff1a; 工具通过功能安全认证自己做测试&#xff0c;开发说明书等&#xff08;适用于自研的工具&#…

上海人工智能实验室代表的国家科研模式创新

本文转载自AI科技评论,真实性由 AI科技评论 负责。 文章目录 1. 人工智能科研模式创新2. 候选人特征Reference2023 年 12 月,上海人工智能实验室第一位主任汤晓鸥意外逝世。汤博士的突然离世令人惋惜,其离世后,上海人工智能实验室的主任位置也一直空缺至今。 1. 人工智能科…

前端标记语言HTML

HTML&#xff08;HyperText Markup Language&#xff09;是一种用于创建网页的标准标记语言。它是构建和设计网页及应用的基础&#xff0c;通过定义各种元素和属性&#xff0c;HTML使得开发者能够组织和格式化文本、图像、链接等内容。 HTML的基本结构 文档类型声明&#xff0…

Tomcat 8.5.100 配置多证书多域名

Tomcat多证书多域名必须是Tomcat 8.5以上版本 配置server.xml <?xml version1.0 encodingutf-8?><Server port"8005" shutdown"SHUTDOWN"><Listener className"org.apache.catalina.startup.VersionLoggerListener" /><…

Docker搭建Fleet

Fleet 是一个高度可伸缩的容器管理工具&#xff0c;它允许用户在一组机器上管理容器。它的设计目的是为了简化在多个Docker宿主之间部署和管理容器的过程。Fleet 可以在整个集群中自动分配资源&#xff0c;确保应用程序的高可用性&#xff0c;并提供服务发现的功能。 应用场景…

Android USB TP方向修改

搜集的一些关于Android USB TP的方向修改的代码&#xff0c;X to Y , X反转 &#xff0c; Y反转&#xff0c;双触屏配置&#xff0c;双屏异触等。 diff --git a/kernel/drivers/hid/hid-multitouch.c b/kernel/drivers/hid/hid-multitouch.c old mode 100644new mode 100755 i…

EtherCAT主站SOEM -- 29 -- STM32F767-SOEM通过 CSP模式(周期同步位置模式)控制一个电机转圈圈

EtherCAT主站SOEM -- 29 -- STM32F767-SOEM通过 CSP模式(周期同步位置模式)控制一个电机转圈圈 0 QT-SOEM视频预览及源代码下载:0.1 QT-SOEM视频预览0.2 QT-SOEM源代码下载1 程序文件修改替换1.1 allvalue.h1.2 allvalue.c1.3 motrorcontrol.h1.4 motrorcontrol.cpp1.5 main…

QT drawPixmap和drawImage处理图片模糊问题

drawPixmap和drawImage显示图片时&#xff0c;如果图片存在缩放时&#xff0c;会出现模糊现象&#xff0c;例如将一个100x100 的图片显示到30x30的区域&#xff0c;这个时候就会出现模糊。如下&#xff1a; 实际图片&#xff1a; 这个问题就是大图显示成小图造成的像素失真。 当…

【笔试】02

TCP TCP&#xff08;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议 它能够提供以下服务&#xff1a; 可靠传输 通过序列号、确认应答、重传机制等确保数据完整、准确地从发送端传输到接收端。 三次握手&#xff1a; 点对点全双工面向字节流…

1260. 二维网格迁移

1260. 二维网格迁移 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a;错误经验吸取 原题链接&#xff1a; 1260. 二维网格迁移 https://leetcode.cn/problems/shift-2d-grid/description/ 完成情况&#xff1a; 解题思路&#xff1a; 这…