1、什么是生产者-消费者模式?
在实际开发过程中,我们可能遇到如下场景:某些模块负责生产数据,某些模块负责处理数据,这些模块可能是一些进程、线程、类或者是函数。其中生产数据的模块称之为生产者,处理数据的模块称之为消费者。
上面的描述还不能解释生产者-消费者模式,该模式在生产者和消费者之间还需要一个缓冲区,生产者把数据放入缓冲区,消费者从缓冲区取出数据。
为了更好的理解该模式,我们举一个生活中的例子,假如你要寄一封信,大致的流程如下:
- 你把信写好——相当于生产者生产数据
- 你把写好的信放入邮箱——相当于生产者把数据放入缓冲区
- 快递员从邮箱中取出信件——相当于消费者从缓冲区取出数据
- 快递员把信拿到邮局做相应的处理——相当于消费者处理数据
这样一解释是不是更加清楚、通俗易懂呢。
2、该模式有什么作用?
解释清楚什么是生产者-消费者模式之后,我们应该有这些的疑问:这个模式有什么用呢?生产者和消费者之间为什么还要一个缓冲区呢,生产者生产数据后直接通知消费者处理数据不就完事了吗?等等。
1、解耦
假设生产者和消费者是两个类,它俩之间不存在缓冲区,那么当生产者生产数据后直接调用消费者类的某个方法去处理数据,生产者就会严重依赖消费者(耦合),如果有一天消费者类中的业务逻辑发生变化,那么可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间就不存依赖关系,耦合也就降低了。
2、支持并发
该模式最好的优势就是处理高并发。在该模式下,生产者和消费者是两个独立运作的个体,生产者把数据往缓冲区一丢,就可以立即去生产下一个数据,不用等待消费者去处理。
如果缓冲区不存在,那么每次生产者生产数据直接调用消费者去处理数据,只有消费者处理完数据后生产者才能继续生产下一个数据,这就造成了阻塞。
3、Node实现一个简单的案例
在实现该模式之前需要注意以下两点:
- 当数据填满缓冲区后生产者就不能继续生产数据了,此时应该让他休眠,等缓冲区不满时唤醒生产者。
- 当缓冲区数据为空时,消费者取不到数据,此时应该让他休眠,等待缓冲区有数据时再唤醒消费者。
本文基于napajs
模块实现生产者-消费者模式:
想了解napajs
模块可以参考:
https://github.com/microsoft/napajs
https://juejin.im/post/59e9b8faf265da430b7a5efd
const napa = require('napajs')
// 创建生产者和消费者线程
var producer = napa.zone.create('producer', {workers: 2})
var consumer = napa.zone.create('consumer', {workers: 2})
// 创建共享区
var store = napa.store.create('store')
store.set('value', 0) // 产品数量
store.set('size', 5) // 缓冲区大小
function sleep() {
return new Promise(resolve => {
setTimeout(resolve, 1000)
})
}
// 生产
function produce() {
var store = global.napa.store.get('store')
while(1) {
if (store.get('value') < store.get('size')) {
store.set('value', store.get('value') + 1)
sleep().then(() => {
console.log('生产者加一操作')
})
} else {
continue
}
}
}
// 消费
function consume() {
var store = global.napa.store.get('store')
while(1) {
if (store.get('value') > 0) {
store.set('value', store.get('value') - 1)
sleep().then(() => {
console.log('消费者减一操作')
})
} else {
continue
}
}
}
// 注册方法
producer.broadcast(produce.toString())
consumer.broadcast(consume.toString())
// 执行
producer.execute(() => {global.produce()})
consumer.execute(() => {global.consume()})
上述代码不一定正确,因为本人在引入napajs
过程中遇到了一些棘手问题,仅仅作为示例加深理解。
在网站上搜到一篇博客使用napajs
实现了该模式,可以借鉴参考:
https://blog.csdn.net/changhuzhao/article/details/78422336
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。