生产者消费者问题

共享内存和消息队列原理详解

余生颓废 提交于 2019-12-01 16:06:33
操作系统内的并发执行进程可以是独立的也可以是协作的: 如果一个进程不能影响其他进程或受其他进程影响,那么该进程是独立的,换句话说,不与任何其他进程共享数据的进程是独立的; 如果一个进程能影响其他进程或受其他进程所影响,那么该进程是协作的。换句话说,与其他进程共享数据的进程为协作进程。 提供环境允许进程协作,具有许多理由: 信息共享:由于多个用户可能对同样的信息感兴趣(例如共享文件),所以应提供环境以允许并发访问这些信息。 计算加速:如果希望一个特定任务快速运行,那么应将它分成子任务,而每个子任务可以与其他子任务一起并行执行。注意,如果要实现这样的加速,那么计算机需要有多个处理核。 模块化:可能需要按模块化方式构造系统,即将系统功能分成独立的进程或线程。 方便:即使单个用户也可能同时执行许多任务。例如,用户可以并行地编辑、收听音乐、编译。 协作进程需要有一种 进程间通信机制(简称 IPC) ,以允许进程相互交换数据与信息。进程间通信有两种基本模型:共享内存和消息传递(消息队列): 共享内存模型会建立起一块供协作进程共享的内存区域,进程通过向此共享区域读出或写入数据来交换信息。 消息传递模型通过在协作进程间交换消息来实现通信。 图 1 给出了这两种模型的对比。 图 1 通信模型   上述两种模型在操作系统中都常见,而且许多系统也实现了这两种模型。消息传递对于交换较少数量的数据很有用

生产者消费者模型

梦想与她 提交于 2019-12-01 13:29:01
一、什么是生产者消费者模型   生产者消费者模型就是通过一个容器解决它们之间的强耦合问题,生产者与消费者之间依靠阻塞队列进行通讯,生产者与消费者之间不直接通讯,这样平衡了二者之间的处理能力,这里使用了进程、线程以及生成器实现了生产者消费者模型。   在进程中分别开启了生产者和消费者的进程,它们之间的通讯依赖进程中的队列Queue来实现的。在线程中分别开启了生产者和消费者线程,它们之间的通讯依赖queue中的Queue完成通讯。协程的使用生成器简单的实现。   使用进程的方式会耗费大量cpu的资源(包括进程的创建、切换、销毁);线程的方式相比进程来讲切换会较少损耗cpu的资源;协程的方式理论上来讲cpu的利用率达到100%,所以协程应该是较为理想的选择。 二、使用进程实现生产者消费者模型 from multiprocessing import Process from multiprocessing import Queue def producer(q, name): # 生产者生产20个数据 for i in range(20): q.put(str(i)) print("%s生产第%s个" % (name, i)) def consumer(q, name): while True: # 从队列中获取数据 data = q.get() if data: print("%s消费第

1-7 生产者消费者模型

倖福魔咒の 提交于 2019-12-01 06:42:53
一 生产者消费者模型介绍 为什么要使用生产者消费者模型 生产者指的是生产数据的任务,消费者指的是处理数据的任务,在并发编程中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。 什么是生产者和消费者模式 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。 这个阻塞队列就是用来给生产者和消费者解耦的 二 生产者消费者模型实现 基于上一小节学习的队列来实习一个生产者消费者模型 from multiprocessing import Process,Queue import time,random,os def consumer(q,name): while True: res=q.get() time.sleep(random.randint(1,3)) print('\033[43m%s 吃 %s\033[0m' %(name,res)) def producer(q,name

spring+rabbitmq的简单实现和延迟队列实现

若如初见. 提交于 2019-11-30 22:02:19
最近项目开发中遇到两个问题,第一个是:订单创建后,5分钟没有付款,则取消订单。第二个是:每天晚上跑spring的定时任务,更新用户的访问次数。由于用户量多,用户访问记录表庞大且是分表,所以更新起来非常耗时,于是决定使用队列解决这两个问题。 使用rabbitmq,设置延时(需额外的插件),可以实现第一个问题。代码中我只需将用户信息取出,然后塞到队列中,由消费者慢慢消化队列,可以缓解第二个问题,下面,我们步入正题。 首先,我们创建一个消息生产者。消息生产者,顾名思义,就是产生消息的bean。我们需要在代码中生成自己需要的信息,可能是多个,以参数的形式,一个一个传递给消息生产者,然后消息生产者将消息一个一个放入队(quque),通过路由器(exchange)再转发给消费者。队列中的信息会一个一个传给消费者,只有消费者处理完这个信息,队列中的下一个信息才会继续传入。 生产者: import java.io.IOException; import javax.annotation.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.stereotype

线程同步

淺唱寂寞╮ 提交于 2019-11-30 21:19:52
目录 线程同步问题 原因: 解决方法: 同步代码块 语法: 锁对象: 锁类: 同步方法 面试题:同步块和同步方法的区别 同步锁 Lock接口 用法 性能: 总结: 线程的死锁 可能出现的原因: 线程的等待和通知 等待: 通知: 注意: 机制: 面试题:wait和sleep的区别 生产者消费者设计模式 几个重要点: 思路: 线程池 API: 作业: wait 和 notify 的调用必须是同一个对象调用。谁让他等待了,谁才能让他唤醒。解铃还须系铃人。 线程同步问题 多个线程同时访问一个资源 原因: 多个线程的执行是抢占式的,当一个线程执行方法时,可能会被另一个线程抢占CPU,当前线程的操作不能完整的执行,导致数据出现问题。 public void transfer(int from,int to,int money){ //一个线程扣除一个账户一定金额,准备给另一个账户加钱 //被其他线程抢占CPU执行,其他线程执行完转账后,前面线程扣的钱还没有加 //统计钱总数就出现问题 accounts[from] -= money; System.out.println("从"+from+"转到"+to+"账户"+money); accounts[to] += money; System.out.println("银行的总账是:" + sum()); } 解决方法:

如何在 Java 中正确使用 wait, notify 和 notifyAll – 以生产者消费者模型为例

北战南征 提交于 2019-11-30 17:49:13
wait, notify 和 notifyAll,这些在多线程中被经常用到的保留关键字,在实际开发的时候很多时候却并没有被大家重视。本文对这些关键字的使用进行了描述。 在 Java 中可以用 wait、notify 和 notifyAll 来实现线程间的通信。举个例子,如果你的Java程序中有两个线程——即生产者和消费者,那么生产者可以通知消费者,让消费者开始消耗数据,因为队列缓冲区中有内容待消费(不为空)。相应的,消费者可以通知生产者可以开始生成更多的数据,因为当它消耗掉某些数据后缓冲区不再为满。 我们可以利用wait()来让一个线程在某些条件下暂停运行。例如,在生产者消费者模型中,生产者线程在缓冲区为满的时候,消费者在缓冲区为空的时候,都应该暂停运行。如果某些线程在等待某些条件触发,那当那些条件为真时,你可以用 notify 和 notifyAll 来通知那些等待中的线程重新开始运行。不同之处在于,notify 仅仅通知一个线程,并且我们不知道哪个线程会收到通知,然而 notifyAll 会通知所有等待中的线程。换言之,如果只有一个线程在等待一个信号灯,notify和notifyAll都会通知到这个线程。但如果多个线程在等待这个信号灯,那么notify只会通知到其中一个,而其它线程并不会收到任何通知,而notifyAll会唤醒所有等待中的线程。 在这篇文章中你将会学到如何使用

网络编程之并发编程——生产者消费者模型

跟風遠走 提交于 2019-11-30 12:52:08
网络编程之并发编程——生产者消费者模型 一、生产者消费者模型介绍 为什么要使用生产者消费者模型? 生产者指的是生产数据的任务,消费者指的是处理数据的任务。在并发编程中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,俺么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。 什么是生产者和消费者模式? 生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。 这个阻塞队列就是用来给生产者和消费者解耦的。 二、生产者消费者模型实现 基于上一小节学习的队列来实现一个生产者消费者模型: from multiprocessing import Process,Queue import time,random,os def consumer(q,name): while True: res=q.get() time.sleep(random.randint(1,3)) print('\033[43m%s 吃 %s\033[0m' %(name,res

基于进程的并发

笑着哭i 提交于 2019-11-30 07:44:41
基于进程的并发 一、什么是进程 进程指的是应用的执行实例,比如,双击桌面上的Internet浏览器图标就会开启一个运行该浏览器的进程。 二、进程与程序的区别 程序仅仅只是一堆代码而已,而进程指的是程序的运行过程。 进程一般由程序、数据集、进程控制块三部分组成。 举个例子:一位厨师正在做蛋糕,他有做蛋糕的食谱和所需的原料,做到一半的时候这位厨师的儿子玩耍受伤了,于是这位厨师放下手头工作并记录他按照食谱做到哪儿了(保存进程的当前状态),然后拿出一本急救手册,按照其中的指示处理伤口。当伤口处理完之后,这位厨师又回来做蛋糕,从他离开时的那一步继续做下去。 在这个例子中:做蛋糕的食谱相当于程序,厨师就是处理器cpu,而做蛋糕的所需原料就是数据集,进程就是厨师阅读食谱、取来各种原料以及烘制蛋糕等一系列动作的总和。 三、并发与并行 无论是并行还是并发,在用户看来都是同时运行的,不管是进程还是线程,都只是一个任务而已,真是干活的是cpu,cpu来做这些任务,而一个cpu同一时刻只能执行一个任务。 并发是指系统具有处理多个任务(动作)的能力,是伪并行,即看起来是用时运行。单个cpu+多道技术就可以实现并发,其实并行也属于并发。 并行是指系统具有同时处理多个任务(动作)的能力,是同时运行,只有具备多个cpu才能实现并行。 单核下,可以利用多道技术。多个核中的每个核也都可以利用多道技术。 有四个核

2.RabbitMQ 的可靠性消息的发送

喜你入骨 提交于 2019-11-30 06:10:43
本篇包含 1、 RabbitMQ 的可靠性消息的发送 2、 RabbitMQ 集群的原理与高可用架构的搭建 3、 RabbitMQ 的实践经验 上篇包含 1、MQ 的本质,MQ 的作用 2、RabbitMQ 的特性,工作模型,交换机详解 3、Java API 编程,UI 管理界面 4、进阶知识:TTL、死信队列、延迟队列,服务端流控和消费端限流 5、Spring AMQP 核心组件 1. RabbitMQ 可靠性投递与高可用架构 1.1. 可靠性投递 在代码里面一定是先操作数据库再发送消息。避免因为数据库回滚导 致的数据不一致。 但是如果先操作数据,后发送消息,发送消息出了问题,那不是一样 会出现业务数据的不一致? 分析 RabbitMQ 的可靠性投递,也就是在使用 RabbitMQ 实现异步通 信的时候, 消息丢了怎么办,消息重复消费怎么办? 在 RabbitMQ 里面提供了很多保证消息可靠投递的机制,这个也是 RabbitMQ 的一 个特性。 我们在讲可靠性投递的时候,必须要明确一个问题,因为效率与可靠性是无法兼得 的,如果要保证每一个环节都成功,势必会对消息的收发效率造成影响。所以如果是一 些业务实时一致性要求不是特别高的场合,可以牺牲一些可靠性来换取效率。 比如发送通知或者记录日志的这种场景,如果用户没有收到通知,不会造成业务影 响,只要再次发送就可以了。

【攻克RabbitMQ】常见问题

拟墨画扇 提交于 2019-11-30 01:35:38
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/zlt995768025/article/details/81938449 消息什么情况下会丢失?配合mandatory参数或备份交换器来提高程序的健壮性 发送消息的交换器并没有绑定任何队列,消息将会丢失 交换器绑定了某个队列,但是发送消息时的路由键无法与现存的队列匹配 预估队列的使用情况? 在后期运行过程中超过预定的阈值,可以根据实际情况对当前集群进行扩容或者将相应的队列迁移到其他集群。 消费消息? 推模式,拉模式 保证消息的可靠性? RabbitMQ 提供了消息确认机制( message acknowledgement)。 消费者在订阅队列时,可以指定 autoAck 参数,当 autoAck 等于 false 时, RabbitMQ 会等待消费者显式地回复确认信号后才从内存(或者磁盘)中移去消息(实质上 是先打上删除标记,之后再删除)。当 autoAck 等于 true 时, RabbitMQ 会自动把发送出去的 消息置为确认,然后从内存(或者磁盘)中删除,而不管消费者是否真正地消费到了这些消息。 在ack为false的情况下,消费者获取消息迟迟没有发送消费者确认消息的信号或者消费者断开,怎么办? 当 autoAck