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

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;

在这里插入图片描述

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

在这里插入图片描述

相关推荐

  1. Go语言并发编程:Goroutines和Channels的详细指南

    2024-07-12 08:56:03       63 阅读
  2. Go语言 Channel

    2024-07-12 08:56:03       29 阅读
  3. Go语言中的Channel

    2024-07-12 08:56:03       48 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-12 08:56:03       70 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-12 08:56:03       74 阅读
  3. 在Django里面运行非项目文件

    2024-07-12 08:56:03       62 阅读
  4. Python语言-面向对象

    2024-07-12 08:56:03       72 阅读

热门阅读

  1. 服务器,云、边缘计算概念简单理解

    2024-07-12 08:56:03       21 阅读
  2. 序列化Serialization

    2024-07-12 08:56:03       24 阅读
  3. jEasyUI 创建折叠面板

    2024-07-12 08:56:03       22 阅读
  4. Postman超时设置全指南:掌控请求等待的艺术

    2024-07-12 08:56:03       38 阅读
  5. 时间复杂度

    2024-07-12 08:56:03       28 阅读
  6. 735. 小行星碰撞

    2024-07-12 08:56:03       31 阅读