Channel单/多线程通信
  • channel是多个协程之间通讯的管道

    • 一端发送数据,一端接受数据

    • 同一时间只有一个携程可以访问数据,无共享内存模式可以出现的内存竞争

并发并行

并发(concurrency): 两个或多个事件在同一时间间隔发生 并行(parallellism): 两个或多个时间在同一时刻发生

channel单线程消费者生产者模型

思路

生产者端:写入数据写入缓冲区 消费者端:从缓冲区读取数据 缓冲区:公共区(商场快递中心)一边放,一边取,但共同点是必须都来到商场或快递中心对数据进行处理。 由生产者,消费者,缓冲区组成的模型称为,生产者消费者模型。 生产者不断放入数据,消费者不断接收数据 当channel中没有数据时,消费者端将会阻塞,等待生产者放入数据。

为什么不让消费者直接从生产者端取数据?设置缓冲区的好处是?

将整个生产者消费者想象成寄快递的过程,生产者是寄件方,消费者是收件方,缓冲区是快递中心。如果没有快递中心,寄件方和收件方能连接吗? 可以,但一旦任意一方发生改变,则需重新连接,也影响了对应的寄/收的。所以经过缓冲区,可以让寄收两方互不影响,降低耦合度。 同时,消费者直接从生产者端取数据也有另一个弊端,函数调用是同步的(阻塞的),当其中一方没有返回前,另一方只好一直等待,无端浪费时间。而添加缓冲区,生产者和消费者是两个独立的并发主体(并发:两个或多个事件在同一时间间隔发生)生产者把快件一丢在缓冲区,就能马上着手下一件快件的准备,不用等待消费者接收,在这个时候增加生产者端(寄件人)数量,将发送的快递数量寄存在快递中心,也不会影响消费者端,提高了并发能力。 当生产者(寄件人)一次性发出过多,消费者不能无法一次性接收过多数据(快件),则可以暂存在缓冲区,等待下一次取回

缓冲区的好处

  • 1、解耦:降低生产者和消费者之间的耦合度(耦合度,两个模块之间的关联程度)

  • 2、并发能力提高:生产者和消费者数量不对等,仍能保持正常通信

  • 3、缓存:生产者和消费者数据处理速度不一致时,可以暂存数据

通过channel充当缓冲区,根据需求选择使用有缓冲/无缓冲通道

有缓冲:要求异步通信 无缓冲:要求同步通信

单线程生产者消费者模型

package main

import (
	"fmt"
	"time"
)

func consumer(in <-chan int) {
	for num := range in {
		fmt.Println("消费者得到数据:", num)
		time.Sleep(time.Second)
	}
}
func producer(out chan<- int) {
	for i := 0; i < 10; i++ {
		data := i * i
		fmt.Println("生产者生产数据:", data)
		out <- data // 数据写入缓冲区
	}
	close(out) //关闭管道
}
func main() {
	//用channel来传递"产品", 不再需要自己去加锁维护一个全局的阻塞队列
	ch := make(chan int, 5) // 添加缓冲区,5,若改成无缓冲ch := make(chan int) ,变成并行操作,生产者等待消费者sleep后才能继续写入数据

	go producer(ch) // 子go程作为生产者
	consumer(ch)    // 主go程作为消费者
}

 

模拟订单

package main

import (
	"fmt"
	"time"
)

type OrderInfo struct { //创建结构体类型OrderInfo
	id int //模拟订单编号
}

func consumer2(in <-chan OrderInfo) { 订单处理,生产者

	for order := range in { //从channel取出订单
		fmt.Println("订单id:", order.id) //模拟处理订单
		time.Sleep(time.Second)
	}
}
func producer2(out chan<- OrderInfo) { //生成订单,生产者

	for i := 0; i < 10; i++ { //循环生成10份订单
		order := OrderInfo{id: i + 1}
		fmt.Println("生产者生产数据:", order)
		out <- order // 数据写入缓冲区
	}
	close(out) //关闭管道
}
func main() {
	//用channel来传递"产品", 不再需要自己去加锁维护一个全局的阻塞队列
	ch := make(chan OrderInfo) // 添加缓冲区,5,若改成无缓冲ch := make(chan OrderInfo) ,变成并行操作,生产者等待消费者sleep后才能继续写入数据

	go producer2(ch) // 子go程作为生产者
	consumer2(ch)    // 主go程作为消费者

}