前面已经讲过很多Golang系列知识,包括并发,锁等内容,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html

接下来讲几个golang常见的并发模型,今天先说说生产者消费者模型。

生产者消费者模型

 

生产者:发送数据端

消费者:接收数据端

缓冲区:
  1. 解耦(降低生产者和消费者之间耦合度)

  2. 并发(生产者消费者数量不对等时,能保持正常通信)

  3. 缓存(生产者和消费者 数据处理速度不一致时,暂存数据)

如何实现?

生产者消费者模型是非常常见的并发模型,而且golang提供了chan类型,可以很方便的实现。

根据 golang的官方文档,使用chan就可以实现生产者和消费者之间的数据和状态同步。

  • 通过chan在生产者和消费者之间传递数据(ch)和同步状态(done);
  • chan作为参数传递时是引用传递,不需要使用指针;
  • chan是协程安全的,多个goroutine之间不需要锁;
  • chan的close事件可以被recv获取,close事件一定在正常数据读完之后,机制类似于read到EOF;
示例代码:

package main

import "fmt"

func Producer(ch chan int) {
  for i := 1; i <= 10; i++ {
    ch <- i
  }
  close(ch)
}

func Consumer(id int, ch chan int, done chan bool) {
  for {
    value, ok := <-ch
    if ok {
      fmt.Printf("id: %d, recv: %d\n", id, value)
    } else {
      fmt.Printf("id: %d, closed\n", id)
      break
    }
  }
  done <- true
}

func main() {
  ch := make(chan int, 3)

  coNum := 2
  done := make(chan bool, coNum)
  for i := 1; i <= coNum; i++ {
    go Consumer(i, ch, done)
  }

  go Producer(ch)

  for i := 1; i <= coNum; i++ {
    <-done
  }
}

运行结果:
id: 2, recv: 1
id: 1, recv: 2
id: 1, recv: 4
id: 1, recv: 5
id: 1, recv: 6
id: 2, recv: 3
id: 2, recv: 8
id: 2, recv: 9
id: 2, recv: 10
id: 2, closed
id: 1, recv: 7
id: 1, closed

 

简单说明:

1、首先创建一个双向的channel,

2.、然后开启一个新的goroutine,把双向通道作为参数传递到producer方法中,同时转成只写通道。子协程开始执行循环,向只写通道中添加数据,这就是生产者。

3、主协程,直接调用consumer方法,该方法将双向通道转成只读通道,通过循环每次从通道中读取数据,这就是消费者。

注意:channel作为参数传递,是引用传递。

缓冲区的好处

1:解耦
假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会直接影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合度也就相应降低了。

2:处理并发
生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者只能无端浪费时间。
使用了生产者/消费者模式之后,生产者和消费者可以是两个独立的并发主体。生产者把制造出来的数据往缓冲区一丢,就可以再去生产下一个数据。基本上不用依赖消费者的处理速度。
其实最当初这个生产者消费者模式,主要就是用来处理并发问题的。

3:缓存
如果生产者制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。

 

最后

以上,就把golang生产者消费者模型简单介绍完了,希望能对大家有所帮助。

Golang 入门系列(十七)几个常见的并发模型——生产者消费者模型的更多相关文章

  1. golang实现生产者消费者模型

    生产者消费者模型分析 操作系统中的经典模型,由若干个消费者和生产者,消费者消耗系统资源,生产者创造系统资源,资源的数量要保持在一个合理范围(小于数量上限,大约0).而消费者和生产者是通过并发或并行方式 ...

  2. Golang 入门系列(十五)如何理解go的并发?

    前面已经讲过很多Golang系列知识,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html, 接下来要说的 ...

  3. Golang 入门系列(十六)锁的使用场景主要涉及到哪些?读写锁为什么会比普通锁快

    前面已经讲过很多Golang系列知识,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html, 接下来要说的 ...

  4. Golang 入门系列(九) 如何读取YAML,JSON,INI等配置文件

    实际项目中,读取相关的系统配置文件是很常见的事情.今天就来说一说,Golang 是如何读取YAML,JSON,INI等配置文件的. 1. json使用 JSON 应该比较熟悉,它是一种轻量级的数据交换 ...

  5. Golang 入门系列(十一)Go语言实现webapi

    之前,已经讲过很多Golang的东西,比如基础语法,mysql的使用,redis的使用等等,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/ca ...

  6. Golang 入门系列(十) mysql数据库的使用

    之前,已经讲过一些Golang的基础的东西,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html, 今天简 ...

  7. Golang 入门系列(八) cron定时任务

    1.cron 表达式的基本格式  Go 实现的cron 表达式的基本语法跟linux 中的 crontab基本是类似的.cron(计划任务),就是按照约定的时间,定时的执行特定的任务(job).cro ...

  8. Golang 入门系列(七) Redis的使用

    安装 1. Redis 的安装很简单,我这里测试直接用的是windows 的版本.如何安装就不细说了.想了解的可以看之前的文章:https://www.cnblogs.com/zhangweizhon ...

  9. Golang 入门系列(五)GO语言中的面向对象

    前面讲了很多Go 语言的基础知识,包括go环境的安装,go语言的语法等,感兴趣的朋友可以先看看之前的文章.https://www.cnblogs.com/zhangweizhong/category/ ...

随机推荐

  1. basename 和 dirname

    basename将目录路径去掉,返回文件的实际文件名(此处也可以是最后一级目录).如与$0一起 if [ $? -eq 0 ]; then cd - ; mv `basename $0` test1. ...

  2. selenium滑块验证

    使用selenium模拟登录解决滑块验证问题   本次主要是使用selenium模拟登录网页端的TX新闻,本来最开始是模拟请求的,但是某一天突然发现,部分账号需要经过滑块验证才能正常登录,如果还是模拟 ...

  3. 用例建模Use Case Modeling

    我的工程实践选题为ESP32低功耗的实现,本项目基于ESP32嵌入式开发平台. 以此题为例,在理解项目需求的基础上进行用例建模,抽取Abstract use case,画出用例图,并确定每一个用例的范 ...

  4. opencv resize图片为正方形尺寸

    在深度学习中,模型的输入size通常是正方形尺寸的,比如300 x 300这样.直接resize的话,会把图像拉的变形.通常我们希望resize以后仍然保持图片的宽高比. 例如: 如果直接resize ...

  5. 【论文阅读】Deep Clustering for Unsupervised Learning of Visual Features

    文章:Deep Clustering for Unsupervised Learning of Visual Features 作者:Mathilde Caron, Piotr Bojanowski, ...

  6. kali linux 修改更新源和更新命令

    1.修改sources.list源文件: vim /etc/apt/sources.list #aliyun 阿里云 deb http://mirrors.aliyun.com/kali kali-r ...

  7. 【Java实例】使用Thumbnailator生成缩略图(缩放、旋转、裁剪、水印)

    1 需求 表哥需要给儿子报名考试,系统要求上传不超过30KB的图片,而现在的手机随手一拍就是几MB的,怎么弄一个才30KB的图片呢? 一个简单的办法是在电脑上把图片缩小,然后截屏小图片,但现在的电脑屏 ...

  8. “word无法创建工作文件,请检查临时环境变量”的解决办法

    问       题:word无法创建工作文件,请检查临时环境变量 解决方法: 1.运行regedit,打开注册表: 2.找到 ⑴.HKEY_USERS\S-1-5-19\Software\Micros ...

  9. WPF最简单的分页控件

    背景:最近在写项目的时候需要写一个简单的分页功能,因项目需要,没有改为MVVM模式,只需要在后台实现 1.呈现效果如下: 接下来就来上代码,看看怎么实现的 1.界面代码 <StackPanel ...

  10. Flask使用bootstrap为HttpServer添加上传文件功能

    关于模态框 使用bootstrap实现点击按钮弹出窗口,简直不要太简单.我们只需要将写好的窗口内容隐藏,然后调用bootstrap的框架即可,简单几行就能完成相关功能实现.... 前提条件是,我们需要 ...