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

ops/2024/10/18 10:05:46/

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.ppmy.cn/ops/56629.html

相关文章

关于斯坦福TTT,大家难道没啥可唠的嘛~?

TTT与transformer也好或manba也好它们之间背后的本质思想&#xff0c;表面上来看是对上下文进行状态表征压缩&#xff0c;再细想来看&#xff0c;均是一种对输入自身结构的一种线性建模变换&#xff0c;不过三者间所采用线性建模方法和策略各有不同和优劣&#xff0c;而TTT在这…

昇思学习打卡-12-Vision Transformer图像分类

文章目录 ViT模型学习构建模型Multi-Head AttentionTransformerEncoderpos_embeddingVit部分实现 推理结果 ViT模型学习 Vision Transformer&#xff08;ViT&#xff09;简介 ViT则是自然语言处理和计算机视觉两个领域的融合结晶。在不依赖卷积操作的情况下&#xff0c;依然可…

合合TextIn - 大模型加速器

TextIn是合合信息旗下的智能文档处理平台&#xff0c;在智能文字识别领域深耕17年&#xff0c;致力于图像处理、模式识别、神经网络、深度学习、STR、NLP、知识图谱等人工智能领域研究。凭借行业领先的技术实力&#xff0c;为扫描全能王、名片全能王等智能文字识别产品提供强大…

数字孪生技术在智能家居中的应用

引言 随着物联网&#xff08;IoT&#xff09;、人工智能&#xff08;AI&#xff09;和大数据技术的迅速发展&#xff0c;智能家居已成为现代生活的一个重要组成部分。数字孪生技术作为一种新兴技术&#xff0c;正在为智能家居的优化和升级提供前所未有的机会。本文将探讨数字孪…

安全防御(防火墙)

第二天&#xff1a; 1.恶意程序---一般会具有一下多个或则全部特点 1.非法性&#xff1a;你未经授权它自动运行或者自动下载的&#xff0c;这都属于非法的。那恶意程序一般它会具有这种特点&#xff0c; 2.隐蔽性&#xff1a;一般隐藏的会比较深&#xff0c;目的就是为了防止…

Java Stream API详解:高效处理集合数据的利器

引言 Java 8引入了许多新特性&#xff0c;其中最为显著的莫过于Lambda表达式和Stream API。Stream API提供了一种高效、简洁的方法来处理集合数据&#xff0c;使代码更加简洁明了&#xff0c;且具有较高的可读性和可维护性。本文将深入探讨Java Stream API的使用&#xff0c;包…

51单片机嵌入式开发:9、 STC89C52RC 操作LCD1602技巧

STC89C52RC 操作LCD1602技巧 1 代码工程2 LCD1602使用2.1 LCD1602字库2.2 巧妙使用sprintf2.3 光标显示2.4 写固定长度的字符2.5 所以引入固定长度写入方式&#xff1a; 3 LCD1602操作总结 1 代码工程 承接上文&#xff0c;在原有工程基础上&#xff0c;新建关于lcd1602的c和h…

STM32杂交版(HAL库、音乐盒、闹钟、点阵屏、温湿度)

一、设计描述 本设计精心构建了一个以STM32MP157A高性能单片机为核心控制单元的综合性嵌入式系统。该系统巧妙融合了蜂鸣器、数码管显示器、点阵屏、温湿度传感器、LED指示灯以及按键等多种外设模块&#xff0c;形成了一个功能丰富、操作便捷的杂交版智能设备。通过串口…