生产者消费者模式 php 【转】

时间:2022-07-12 01:16:23

在工作中常常听到某某大牛之间的交谈会涉及到,xx消费者啊啥的,到底什么大牛之间讲的是什么? 
这篇文章主要解决三个问题: 
1.到底什么是生产者和消费者,以及它们之间的故事 
2.它们之间靠什么交流 
3.应用场景

正文

一、什么是生产者和消费者,以及它们之间的故事

在实际的程序开发中,会经常碰到这样的情况:小a模块负责生产数据,这些数据由另外一个模块负责处理。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。

单单抽象出生产者和消费者,还够不上是生产者/消费者模式。该模式还需要有一个缓冲区处于生产者和消费者之间,作为一个中介。生产者把数据放入缓冲区,而消费者从缓冲区取出数据。大概的结构如下图。

生产者消费者模式 php 【转】

可以这么理解,你(生产者)需要写信寄给基友,你先放到邮箱(缓冲区),邮递员(消费者)从邮箱取信进行派送(数据处理)。

那么有同学问了,好好的生产者和消费者直接沟通不就好了,搞出一个缓冲区是做甚? 
其实这是有内涵(优点)的:

解耦

假设生产者和消费者都是两个类,如果直接让生产者调消费者的类的方法,势必会使其依赖于消费者的类方法,万一消费者的消费方式改变(函数改掉啦)那么生产者也要改。好了,代码耦合了。

那么如果有了缓冲区就不一样了,两个都依赖于缓冲区,缓冲区只起到缓冲数据作用,一边存一边取,互不关联也不依赖。

ps:你写信直接交给邮递员,万一邮递员换了,那你不是还要重新认识一下,还要关心是不是真的邮递员。那如果是放邮箱的话,邮递员是谁和你半毛钱关系没有。

支持并发

生产者直接调消费者某个方法有个弊端:由于函数是同步的,也可以说是阻塞的,消费者没返回之前,生产者只能一直等着,万一消费者处理的又很慢,那生产者空闲着就浪费了。 
使用了生产者/消费者模式之后,生产者和消费者可以是两个独立的并发主体。生产者把制造出来的数据往缓冲区一丢,就可以再去生产下一个数据。基本上不用依赖消费者的处理速度。

ps:如果没邮箱,你就要站在等邮递员来,想必这是坑爹的一件事。

支持生产消费者忙闲不均

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

ps:万一今天是情人节啥的,寄信的人特别多,邮递员一回只能带100封,那么多余100封的部分就可以放在邮箱,等处理好100封后再回头取,继续处理。

它们之间靠什么交流

那么生产者和消费者之间怎么交流呢?当然是通过数据单元交流的。何谓数据单元捏?简单地说,每次生产者放到缓冲区的,就是一个数据单元;每次消费者从缓冲区取出的,也是一个数据单元。

ps:寄信,信就是数据单元

那么数据单元涉及到一个很关键的问题,就是数据粒度的问题。 
有时出于性能等因素的考虑,也可能会把N个业务对象打包成一个数据单元。那么,这个N该如何取值就是颗粒度的考虑了。颗粒度的大小是有讲究的。太大 的颗粒度可能会造成某种浪费;太小的颗粒度可能会造成性能问题。颗粒度的权衡要基于多方面的因素,以及一些经验值的考量。

ps:还是拿寄信的例子。如果颗粒度过小(比如设定为1),那邮递员每次只取出1封信。如果信件多了,那就得来回跑好多趟,浪费了时间。 
如果颗粒度太大(比如设定为100),那寄信的人得等到凑满100封信才拿去放入邮筒。假如平时很少写信,就得等上很久,会很不爽滴~

应用场景

那么在php中哪些地方会用到呢,或者说哪些地方会看到别人用到生产者和消费者模式?这里简单讲几个:

swoole

对,你没看错,就是swoole。那么swoole其实是有使用了这个设计的模式,业务逻辑(生产者)将数据单元通过swoole的send函数弄到swoole的一个缓冲区之间,通过work进程进行分发,task进程(消费者)进行消费。

耗时操作的异步处理

当“耗时操作“遇到了”高并发“,如果不采取一点措施,卡慢崩会慢慢到来,此时可以将要处理的耗时操作的相关信息(数据单元)通过业务逻辑[生产者]push到redis队列中(redis只是举例),在通过跑一个脚本的进程[消费者]进行pop出数据单元进行处理。

转载自

http://blog.csdn.net/u011957758/article/details/51138707