posted at 2022.11.4 13:01 by Administrator
并发编程是异步编程的功能之一,异步是所有编程语言都具备的语法之一,它是在不影响主程序执行的情况下独自执行某段代码完成某个功能,在执行过程中可能会占用主程序的某些资源,如数据、文件对象等。
Goroutine包是Go语言的特色,它的基本对象为M、G、P,也称为GPM模型。
M代表一个线程,G所有的任务最终是在M上执行的。
G代表一个Goroutine对象,每个调用的时候都会创建一个G对象,主要为M提供运行环境和程序调度。
P代表一个处理器,运行每一个M都必须绑定一个P。
Go语言的并发编程除了Goroutine之外,还包括通道、分配器和GC等功能。
在并发编程中,使用生产者和消费者模式能够解决大多数并发问题,该模式通过平衡生产和消费的工作能力,来提高程序整体处理数据的速度。
生产者生产数据,消费者消费数据,在并发编程中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题,引入了生产者和消费者模式。
生产者和消费者模式通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通信,而是使用一个消息队列来进行通信,所以生产者生产完数据之后不用等待消费者处理,而是直接扔给消息队列;消费者不找生产者获取数据,而是直接从消息队列获取。
消息队列相当于一个缓冲区,平衡了生产者和消费者的处理能力,
在生产环境中有许多分布式消息队列,例如RabbitMQ、RocketMq、Kafka等。在原理阐述过程中,没必要使用这些大型的消息队列,直接使用Go语言的通道即可。
为了更深刻地理解生产者和消费者模式,我们模拟一个餐厅的实际场景,生产者可视为餐厅的厨师,他们的生产数据视为烹饪菜式,消费者可视为餐厅的顾客,他们的消费数据视为食用菜式。实现代码如下:
packagemainimport("fmt""sync""time") //创建同步等待组对象var waiting sync.WaitGroup func producer(intChan chan int,exitChan chan bool){//往通道intChan写入数据,每两秒执行一次写入for i:=0;i<cap(intChan);i++{fmt.Printf("厨师完成菜式%v的制作\n",i)intChan<-itime.Sleep(2*time.Second)}//往通道exitChan写入数据exitChan<-truefmt.Printf("厨师完成所有菜式\n")//代表完成并发,同步等待组的等待对象减一waiting.Done()} func consumer(intChan chan int,exitChan chan bool){//设置标签fors:for{ //监听通道intChan和exitChanselect{case v, _:=<-exitChan:if v{fmt.Printf("厨师下班,店铺不经营!\n")//终止标签fors的循环//不能直接使用break//因为case语句里面使用break默认对case有效break fors} case v, ok:=<-intChan:if ok{ fmt.Printf("顾客吃了菜式%v!\n",v)}default:fmt.Printf("顾客等待中...\n")time.Sleep(3*time.Second) }}//代表完成并发,同步等待组的等待对象减一waiting.Done()} func main(){//设置同步等待组最大的等待数量waiting.Add(2)//定义通道变量intChan和exitChanintChan:=make(chan int,3)exitChan:=make(chan bool)//创建两个Goroutine,分别代表生产者和消费者go producer(intChan,exitChan)go consumer(intChan,exitChan)//主程序进入阻塞状态,等待并发程序执行完成fmt.Printf("main进入阻塞状态..等待并发程序结束\n")waiting.Wait()fmt.Printf("main解除阻塞\n") }
上述示例设置了3个函数:producer() 、consumer()和 main(),每个函数说明如下:
producer()实现生产者功能,参数intChan和exitChan为通道类型,intChan存储生产者产生的数据,exitChan代表生产者完成生产之后的状态。函数通过for循环将数据依次写入通道intChan,循环结束后再设置通道exitChan。
consumer()实现消费者功能。producer()和consumer()通过参数intChan和exitChan实现数据通信。consumer()通过for死循环方式监听通道。
主函数main()设置全局变量waiting,让主程序等待并发程序完成执行,然后定义通道变量intChan和exitChan,将通道变量作为producer()和consumer()的参数,并以并发形式执行函数producer()和consumer()。
运行上述代码,效果如下:
5a725f9f-d895-4fb9-a742-09d9b2fc3cf2|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04
Tags: 程序, 代码, 数据, 类, 模
IT技术