今天打算来介绍一下“生产者/消费者模式”,这玩意儿在很多开发领域都能派上用场。由于该模式很重要,打算分几个帖子来介绍。今天这个帖子先来扫盲一把。如果你对这个模式已经比较了解,请跳过本扫盲帖,直接看下一个帖子(关于该模式的具体应用)
。<!-- program-think-->
看到这里,可能有同学心中犯嘀咕了:在四人帮(GOF)的23种模式里面似乎没听说过这种嘛!其实GOF那经典的23种模式主要是基于OO的(从书名《Design Patterns: Elements of Reusable Object-Oriented
Software》就可以看出来)。而Pattern实际上即可以是OO的Pattern,也可以是非OO的Pattern的。
★简介
言归正传!在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块
是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者
;而处理数据的模块,就称为消费者
。
单单抽象出生产者和消费者,还够不上是生产者/消费者模式。该模式还需要有一个缓冲区处于生产者和消费者之间,作为一个中介。生产者把数据放入缓冲区,而消费者从缓冲区取出数据。大概的结构如下图。
为了不至于太抽象,我们举一个寄信的例子(虽说这年头寄信已经不时兴,但这个例子还是比较贴切的)。假设你要寄一封平信,大致过程如下:
1、你把信写好——相当于生产者制造数据
2、你把信放入邮筒——相当于生产者把数据放入缓冲区
3、邮递员把信从邮筒取出——相当于消费者把数据取出缓冲区
4、邮递员把信拿去邮局做相应的处理——相当于消费者处理数据
★优点
可能有同学会问了:这个缓冲区有什么用捏?为什么不让生产者直接调用消费者的某个函数,直接把数据传递过去?搞出这么一个缓冲区作甚?
其实这里面是大有讲究的,大概有如下一些好处。
◇解耦
假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。
接着上述的例子,如果不使用邮筒(也就是缓冲区),你必须得把信直接交给邮递员。有同学会说,直接给邮递员不是挺简单的嘛?其实不简单,你必须得认识谁是邮递员,才能把信给他(光凭身上穿的制服,万一有人假冒,就惨了)。这就产生和你和邮递员之间的依赖(相当于生产者和消费者的强
耦合)。万一哪天邮递员换人了,你还要重新认识一下(相当于消费者变化导致修改生产者代码)。而邮筒相对来说比较固定,你依赖它的成本就比较低(相当于和缓冲区之间的弱
耦合)。
◇支持并发(concurrency)
生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者就会白白糟蹋大好时光。
使用了生产者/消费者模式之后,生产者和消费者可以是两个独立的并发主体(常见并发类型有进程和线程两种,后面的帖子会讲两种并发类型下的应用)。生产者把制造出来的数据往缓冲区一丢,就可以再去生产下一个数据。基本上不用依赖消费者的处理速度。
其实当初这个模式,主要就是用来处理并发问题的。
从寄信的例子来看。如果没有邮筒,你得拿着信傻站在路口等邮递员过来收(相当于生产者阻塞);又或者邮递员得挨家挨户问,谁要寄信(相当于消费者轮询)。不管是哪种方法,都挺土的。
◇支持忙闲不均
缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。
为了充分复用,我们再拿寄信的例子来说事。假设邮递员一次只能带走1000封信。万一某次碰上情人节(也可能是圣诞节)送贺卡,需要寄出去的信超过1000封,这时候邮筒这个缓冲区就派上用场了。邮递员把来不及带走的信暂存在邮筒中,等下次过来时再拿走。
费了这么多口水,希望原先不太了解生产者/消费者模式的同学能够明白它是怎么一回事。然后在下一个帖子中,我们来说说如何确定数据单元
。
另外,为了方便阅读,把本系列帖子的目录整理如下:
1、如何确定数据单元
2、队列缓冲区
3、环形缓冲区
4、双缓冲区
5、......
版权声明
本博客所有的原创文章,作者皆保留版权。转载必须包含本声明,保持本文完整,并以超链接形式注明作者编程随想
和本文原始地址:
http://program-think.blogspot.com/2009/03/producer-consumer-pattern-0-overview.html
分享到:
相关推荐
#### 一、设计模式概述 在开发较为复杂的LabVIEW项目时,设计模式(Design Patterns)起着至关重要的作用。设计模式是一种经过验证的解决方案,它帮助开发者解决常见的软件设计问题。通过合理地利用设计模式,可以...
1. **增强的幂等性**:生产者现在可以配置为幂等模式,保证在重复发送消息的情况下,主题中的数据保持一致。 2. **消费者位移管理**:消费者位移现在默认存储在Kafka主题中,提高了消费者恢复速度和故障转移的可靠...
1. **电商企业案例**:通过优化组织架构、职能架构和业务流程等要素,实现了从供应商到消费者的全链条数字化运营,大幅提高了业务效率和客户满意度。 2. **制造企业案例**:围绕“智能制造”战略目标,对组织架构、...
在本架构中,可以采用生产者-消费者模式来实现高效的资源管理和任务调度。具体来说,登录服务器和大厅服务器可以使用简单的线程池来处理用户的请求;而游戏服务器则需要更复杂的线程模型来支持游戏逻辑的高效执行。 ...
ControlBusTM打破了传统的主/从通讯模式,采用并行通讯网络的多主生产者/消费者模式,提升了系统的带宽和性能。每个模板都可以作为数据的生产者或消费者,使得控制器能够专注于高级控制任务,而数据交换更加高效。 ...
#### 二、MQSeries编程模式概述 MQSeries提供了多种编程接口,包括但不限于C、C++、Java、COBOL等语言的支持。无论何种规模的应用程序,都可能会用到一些通用的操作模式。这些模式不仅简化了编程流程,还提高了系统...
- **服务发现**:注册中心会将服务提供者的地址列表返回给消费者,并且当有变更时,会通过长连接推送变更数据给消费者。 - **服务调用**:消费者根据提供者的地址列表,通过软负载均衡算法选择一个提供者进行调用。...
- **解耦**:消息队列隔离了生产者和消费者,使得它们可以在不同的时间点操作。 - **可靠性**:消息队列确保消息被可靠地传递给所有订阅者。 - **负载均衡**:消息队列可以平衡多个消费者的负载,提高系统的整体性能...
- **JMS技术简介**:JMS是一种Java平台中的消息中间件规范,用于实现生产者/消费者模式的信息传递。它支持点对点(Point-to-Point, PTP)和发布/订阅(Publish/Subscribe, PUB/SUB)两种消息传递模型。 - **JMS的...
- **表示层(Web)** 如同商场,将食品加工厂生产的“产品”进行包装和展示,提供给消费者(用户)。 通过这种类比,我们可以清晰地看到三层架构如何通过明确的职责划分,实现了软件系统的高内聚、低耦合,从而提升...
然而,我们鼓励下载和审查“架构与开发电子书”,因为在指导中解释的架构风格和架构模式和技术在解释许多模式实现时使用此参考应用程序,因此您将更好地了解上下文,设计以及在当前架构和内部设计中采取的决策。...
* 配合分区的设计,提出消费者组的概念,组内每个消费者并行消费(注意:一个partition中的数据只能由消费者组中的一个group来消费)。 * 为了提高可用性,为了每个partition增加若干个副本。 四、Kafka生产者 ...
BMC模式(Business-Media-Consumer Model),即企业—媒体—消费者模式,是一种通过整合企业、媒体与消费者资源,打造无店铺营销和电子商务相结合的新商业形态。该模式旨在减少传统销售过程中的中间环节,提高效率,...
4. **消费者模型**:Kafka支持多种消费者模型,包括高阶API中的分区分配策略和低阶API的简单消费者模式。 5. **实时处理**:Kafka的消息处理是实时的,适合构建实时数据管道和流处理应用。 **Kafka的组件** 1. **...
### 家具定制模式(C2M)行业分析与顶层架构设计 #### 一、家具行业基础概念及分类 家具是人类生活中不可或缺的一部分,用于满足人们的坐、卧、作业等需求,同时也具备一定的储物和展示功能。根据不同的标准,家具...
B2C模式是一种电子商务模式,指的是商家直接销售商品给消费者。B2C模式的特点是降低了中间商的角色,提高了交易效率和减少了成本。 知识点十:电子商务平台设计 电子商务平台设计是指设计和实现一个电子商务平台的...
- **客户端节点(Client)**: 包括生产者(Producer)和消费者(Consumer),它们分别用于发送和接收消息。客户端可以通过不同的方式连接到工作节点,实现消息的生产和消费。 #### 二、核心概念 **2.1 管理节点...