Go语言---并发编程之channel(双channel,单channel)以及应用实例(生产者消费者、打印机模型)

news2024/11/15 18:01:17

Channel

goroutine 运行在相同的地址空间,因此访问共享内存必须做好同步。goroutine 通过通信来共享内存,而不是其享内存来通信。

引用类型 channel 是CSP 模式的具体实现,用于多个 goroutine 通讯。其内部实现了同步,确保并发安全。

channel类型

和 map 类似,channel 也一个对应 make 创建的底层数据结构的引用。
当我们复制一个 channel或用于函数参数传递时,我们只是拷贝了一个 channel 引用,因此调用者和被调用者将引用同一个channel 对象。和其它的引用类型一样,channel 的零值也是nil。
定义一个 channel 时,也需要定义发送到channel 的值的类型。channel 可以使用内置的 make()函数来创建:

make (chan Type)
make (chan Type,capacity)
  • 当capacity=0,channel是无缓冲阻塞读写的,当capacity>0时,channel有缓存,是非阻塞的,直到写满capacity个元素才阻塞写入。
  • chamnel 通过操作符<-来接收和发送数据,发送和接收数据语法:
channel<-value   //发送value 到channel
<-channel     //接收并将其丢弃
x:=<-channel   //从 channel 中接收数据,并賦偵给x
x,ok:=<-channel   //功能同上,同时检查通道是否已关闭或者是否为空

默认情况下,channel接收和发送数据都是阻塞的,除非另一端已经准备好,这样就使得goroutine 同步变的更加的简单,而不需要显式的lock。

实现

在这里插入图片描述

  • 管道放的位置一个在打印的前面,一个在打印的后面
  • 如果Person2先执行,管道里面没有数据,就会阻塞
  • Person1执行,打印完数据以后,往管道里面输入数据,Person2就会感知到,然后开始打印 。

通过channel实现同步和数据交互

在这里插入图片描述
在这里插入图片描述

无缓冲的 channel

无缓冲的通道(unbuffered channel)是指在接收前没有能力保存任何值的通道。
这种类型的通道要求发送 goroutine 和接收 goroutine 同时准备好,才能完成发送和接收操作。如果两个 goroutine 没有同时准备好,通道会导致先执行发送或接收操作的 goroutine 阻塞等待。
这种对通道进行发送和接收的交互行为本身就是同步的。其中任意一个操作都无法离开另个操作单独存在。
下图展示两个 goroutine 如何利用无缓冲的道来共享一个值:
在这里插入图片描述

  • 也就是channel本身不能存放东西,一个放另一个立马取。
  • 在第1步,两个 goroutine 都到达通道,但哪个都没有开始执行发送或者接收。
  • 在第 2 步,左侧的 goroutine 将它的手伸进了通道,这模拟了向通道发送数据的行为。这时,这个goroutine 会在通道中被锁住,直到交换完成。
  • 在第 3 步,右侧的 goroutine 将它的手放入通道,这模拟了从通道里接收数据。这个goroutine 一样也会在通道中被锁住,直倒交换完成。
  • 在第 4步和第 5步,进行交换,并最终,在第6步,两个 goroutine 都将它们的手从通道里拿出来,这模拟了被锁住的 goroutine 得到释放。两个 goroutine 现在都可以去做别的事情了。

建立无缓冲的channel

make (chan Type)//等价于make (chan Type,0)

如果没有指定缓冲区容量,那么该通道就是同步的,因此会阻塞到发送者准备好发送和接收者准备好援收。

在这里插入图片描述

  • ch<-i往channel中写数据,主协程感知到才会执行,这时候子协程也会阻塞等待,管道读取完数据以后,子协程才会继续。
  • 但是println打印数据,是在管道读取之后,所以打印的快慢是由系统决定的。

有缓冲的channel

有缓冲的通道(buffered channel)是一种在被接收前能存储一个或者多个值的通道。
这种类型的通道并不强制要求 goroutine 之问必须同时完成发送和接收。通道会阻塞发送和接收动作的条件也会不同。只有在通道中没有要接收的值时,接收动作才会阻寒。只有在通道没有可用缓冲区容纳被发送的值时,发送动作才会阻寒。
这导致有缓冲的通道和无缓种的通道之间的一个很大的不同:无缓冲的通道保证进行发送和接收的 goroutine 会在同一时间进行数据交换:有缓冲的通道没有这种保证。
在这里插入图片描述

  • 在第 1步,右侧的 goroutine 正在从通道接收一个值。
  • 在第 2步,右侧的这个 goroutine 独立完成了接收值的动作,而左侧的 goroutine 正在发送一个新值到通道里。
  • 在第 3 步,左侧的 goroutine 还在向通道发送新值,而右侧的 goroutine 正在从通道接收另外一个值。这个步骤里的两个操作既不是同步的,也不会互相阻塞。
  • 最后,在第4步,所有的发送和接收都完成,而通道里还有几个值,也有一些空间可以存更多的值。

创建

make (chan Type,capacity)

如果给定了一个缓冲区容量,通道就是异步的。只要缓冲区有未使用空间用于发送数据,或还包含可以接收的数据,那么其通信就会无阻塞地进行。

实现

在这里插入图片描述

  • 如果存放够了三个,这时就会阻塞等待读取,当主协程读取过一个数据有空闲位置以后,子协程会继续执行,之后的打印顺序就不一定了。
    在这里插入图片描述

关闭channel

channel可以通过ok来检测channel是否还在打开状态,如果channel关闭,就不读数据。

在这里插入图片描述

  • num ,ok:=<-ch可以检测到通道是否关闭。

注意

  • channel不像文件一样需要经常去关闭,只有当你确实没有任何发送数据了,或者你想显式的结束 range 循环之类的,才去关闭 channel;
  • 关闭 channel 后,无法向 channel 再发送数据(引发 panic 错误后导致接收立即返回零值):
  • 关闭 channel后,可以继续向chamnel 接收数据:
  • 对于 nil channel,无论收发都会被阻塞。
    在这里插入图片描述
  • 可以使用range来遍历channel,自动跳出循环
    在这里插入图片描述

单向channel

默认情况下,通道是双问的,也就是,既可以往里面发送数据也可以从里面接收数据。
但是,我们经常见一个通道作为参数进行传递而值希望对方是单向使用的,要么只让它发送数据,要么只让它接收数据,这时候我们可以指定通道的方向。单向 chamel 变量的声明非常简单,如下:

var ch1 chan int //ch1双向
var ch2 chan<-float64 //ch2单向,只能用于写float64数据
var ch3 <-chan int  //ch3单向,只能用于读int数据

chan<-表示数据进入管道,要把数据写进管道,对于调用者就是输出。
<-chan 表示数据从管道出来,对于调用者就是得到管道的数据,当然就是输入。
可以将 channel 隐式转换为单向队列,只收或只发,不能将单向channel转换为普通channel;

在这里插入图片描述

利用单通道,实现生产者消费者模型

在这里插入图片描述

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

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

相关文章

【Linux】磁盘性能压测-FIO工具

一、FIO工具介绍 fio&#xff08;Flexible I/O Tester&#xff09;是一个用于评估计算机系统中 I/O 性能的强大工具。 官网&#xff1a;fio - fio - Flexible IO Tester 注意事项&#xff01; 1、不要指定文件系统名称&#xff08;如/dev/mapper/centos-root)&#xff0c;避…

vue + echart 饼形图

图表配置&#xff1a; import { EChartsOption, graphic } from echarts import rightCircle from /assets/imgs/index/right_circle.png export const pieOption: EChartsOption {title: {text: 100%,subtext: 游客加量,left: 19%,top: 42%,textStyle: {fontSize: 24,color:…

如何评估媒体邀约宣传的效果

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 评估媒体邀约宣传的效果是一个系统而全面的过程&#xff0c;它涉及多个维度的考量和分析。 一、受邀媒体的出席率&#xff1a; 1.受邀媒体出席率直观反映了媒体邀约的效果&#xff1b; …

「C++系列」一篇文章说透【存储类】

文章目录 一、C 存储类1. 类的定义2. 对象的创建3. 对象在内存中的布局4. 对象的存储位置 二、auto 存储类1. auto的基本用法2. auto与存储类的关系1) 自动存储类&#xff08;最常见的&#xff09;2) 静态存储类3) 动态存储类&#xff08;通过new&#xff09; 三、register 存储…

自学第十五天----深入理解函数上

1. 函数是什么&#xff1f; 维基百科中对函数的定义&#xff1a; 子程序 在计算机科学中&#xff0c;子程序&#xff08;英语&#xff1a;Subroutine, procedure, function, routine, method, subprogram, callable unit&#xff09;&#xff0c;是一个大型程序中的某部分代码…

【2-1:RPC设计】

RPC 1. 基础1.1 定义&特点1.2 具体实现框架1.3 应用场景2. RPC的关键技术点&一次调用rpc流程2.1 RPC流程流程两个网络模块如何连接的呢?其它特性RPC优势2.2 序列化技术序列化方式PRC如何选择序列化框架考虑因素2.3 应用层的通信协议-http2.3.1 基础概念大多数RPC大多自…

windows上修改redis端口号

概况 redis是一个开源的内存数据结构存储系统&#xff0c;常用做数据库、缓存和消息代理。默认的端口号为6379 更改redis端口号步骤如下 先停止redis服务 redis-cli shutdowm 打开redis配置文件 在redis安装目录下&#xff0c;即redis.windows.conf文件。 port 6396 然后…

插片式远程 I/O模块:热电阻温度采集模块与PLC配置案例

XD系列成套系统主要由耦合器、各种功能I/O模块、电源辅助模块以及终端模块组成。有多种通讯协议总线的耦合器&#xff0c;例如Profinet、EtherCAT、Ethernet/IP、Cclink IE以及modbus/TCP等。I/O 模块可分为多通道数字量输入模块、数字量输出模块、模拟量输入模块、模拟量输出模…

js前端隐藏列 并且获取值,列表复选框

列表框 <div class"block" id"psi_wh_allocation_m"><table id"result" class"list auto hover fixed" style"width:100%;border-collapse:collapse"><thead><tr><%--<th></th>--%&…

人类大脑的计算与机器的类脑计算

人类大脑的计算基本原理涉及到神经元的基本工作方式、神经网络的结构和连接模式、信息传递的方式、学习和记忆的机制等多个层面的复杂互动&#xff0c;这些原理的深入理解不仅有助于神经科学的发展&#xff0c;还为人工智能领域的发展提供了重要的启示和指导。人类大脑计算基本…

【JavaScript 报错】未捕获的加载错误:Uncaught LoadError

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、错误原因分析1. 资源路径错误2. 资源不存在3. 网络问题 二、解决方案1. 检查资源路径2. 确保资源存在3. 处理网络问题 三、实例讲解四、总结 在JavaScript应用程序中&#xff0c;未捕获的加载错误&#xff08;Uncaught …

电脑录音如何操作?电脑麦克风声音一起录制,分享7款录音软件

电脑录音已经成为我们日常生活和工作中不可或缺的一部分。无论是录制会议、教学、音乐、网络直播、音源采集还是其他声音&#xff0c;电脑录音软件都为我们提供了极大的便利。本文将为大家介绍如何操作电脑录音&#xff0c;并分享七款录音软件&#xff0c;包括是否收费、具体操…

OpenCV中的浅拷贝和深拷贝

文章目录 前言一、浅拷贝二、深拷贝三、比较总结 前言 在数字图像处理中&#xff0c;针对读取到的一张图像&#xff0c;需要反复利用这张图像做各种的变换&#xff0c;以满足我们项目的需求。在这之前&#xff0c;最容易忽略的一点就是图像之间的拷贝问题&#xff0c;其中的浅…

【JavaScript 报错】未捕获的类型错误:Uncaught TypeError

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、错误原因分析1. 调用不存在的方法2. 访问未定义的属性3. 数据类型不匹配4. 函数参数类型不匹配 二、解决方案1. 检查方法和属性是否存在2. 使用可选链操作符3. 数据类型验证4. 函数参数类型检查 三、实例讲解四、总结 在…

Java高级重点知识点-25-Stream流、方法引用

文章目录 Stream流流式思想概述获取流常用方法 方法引用方法引用符通过对象名引用成员方法通过类名称引用静态方法通过super引用成员方法通过this引用成员方法类的构造器引用数组的构造器引用 Stream流 通过循环遍历来讲解流的优势&#xff1b; 要求&#xff1a;筛选所有姓张的…

游戏如何应对黑灰产工作室

游戏黑灰产工作室&#xff0c;是指以非法渠道、非法手段通过游戏进行牟利的团伙。使用脚本、外挂是黑灰产工作室的显著特征&#xff0c;其常见的牟利方式有&#xff1a;打金工作室、资源囤积号、初始号、自抽号、代练工作室以及营销欺诈等。 ▲ 常见的游戏黑灰产工作室牟利路径…

正向传播和反向传播

正向传播&#xff08;Forward Propagation&#xff09; 正向传播是指将输入数据通过神经网络&#xff0c;计算出预测值的过程。具体步骤如下&#xff1a; 输入层&#xff1a;接受输入数据。隐藏层&#xff1a;每个隐藏层中的神经元接收上一层的输出&#xff0c;进行加权求和&…

ENSP防火墙综合配置

综合拓扑&#xff1a; 实验要求&#xff1a; 要求一 生产区的安全策略配置 办公区的安全策略 要求二 生产区的安全策略 游客和办公区的安全策略 因为ISP返回的数据包会被防火墙最后的默认安全策略给拒绝&#xff0c;所以&#xff0c;把要ISP返回的数据给允许通过 要求三 增加…

Lingo学习(三)——工厂合并、运算符、内置函数

一、工厂合并 &#xff08;一&#xff09; 工厂合并——生产二维矩阵 【引入】 sets: factory /1..6/ : a; plant /1..8/ : d; Cooperation(factory,p lant) : c, x; endsets 以上程序可…

Go语言入门之Map详解

Go语言入门之Map详解 1.基础定义 map是一个无序的&#xff0c;k-v键值对格式的集合 &#xff08;1&#xff09;特点 类型特点&#xff1a;map为引用类型&#xff0c;所以在函数中更新value值会永久改变顺序特点&#xff1a;map的遍历是无序的&#xff0c;因为底层是哈希表&am…