# python_demo **Repository Path**: fredricen/python_demo ## Basic Information - **Project Name**: python_demo - **Description**: python操作dll、python操作RabbitMQ - **Primary Language**: Python - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2021-06-11 - **Last Updated**: 2022-06-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # python_demo ## 介绍 - ctypes: python操作dll - rabbitmq: python操作RabbitMQ - HelloWorld: RabbitMQ基本概念,生产者产生消息,消费者获取消息 - WorkQueue: RabbitMQ给多个消费者分配任务,每次任务都是分配给一个消费者 - PublishSubcribe: RabbitMQ给多个消费者分配任务,每次任务可以分配给所有消费者 - Routing: RabbitMQ给指定队列分配任务,消息分发给指定路由的消费者 - Topic: RabbitMQ给符合通配路由模式的对列分配任务,消息分发给匹配路由模式的消费者 - RPC: 使用RabbitMQ搭建RPC服务 ## 说明 dll文件对应的源码: ![dll源码文件](./images/dll_content.png) ## 详情 ### RabbitMQ之HelloWorld 生产者和消费者通过具名队列,进行消息收发 ![helloworld](./images/helloworld.png) 生产者发送消息: ![sending](./images/sending.png) 消费者接收消息: ![receiving](./images/receiving.png) 生产者和消费者,仅仅是一种线程,一个进程(服务器或者客户端)可以同时有生产者和消费者。 ### RabbitMQ之WorkQueue 给多个消费者分配任务,默认采用的轮流机制,即一个消费者分配完,分配另一个,这样的话, 如果有两个消费者,奇数个消息都是费时任务,偶数个消息都是简单任务, 那么会导致一个消费者累死,一个消费者一直空闲的情况,也就是任务分配不均衡。 为了实现均衡分配任务,可以采用basic_qos协议,并且指定每个消费者最多接受一个任务, 这样,当困难任务分配一个消费者,简单任务分配给另一个消费者, 当下一个困难任务过来的时候,执行简单任务的消费者空闲,就分配给这个消费者, 而之前分配到困难任务的消费者继续完成原来的任务,直到完成才接受新任务。 公平分发: ![fair-dispatch](./images/prefetch-count.png) 消息持久化: 为了保证不丢消息,而且保证服务器死机或者处理异常时,消息也不丢失,需要把消息保存到硬盘上,而不是内存中 为了实现持久化,需要队列持久化(durable=True)、消息持久化(dilivery_mode=2) ### RabbitMQ之PublishSubscribe 发布/订阅模式,也就是一个生产者发送消息,多个消费者接收消息 RabbitMQ中消息模型,生产者不能直接发送消息到队列中,而必须经过交换机(exchange), 经过中间交换机的参与,生产者和队列就实现了隔离,生产者不需要知道要发送到哪个队列, 队列也不需要知道消息来自哪个生产者。 交换机模型: ![exchange](./images/exchanges.png) 生产者必须把消息发送给交换机。交换机一方面接收消息,一方面决定把消息发送到哪个队列。根据发送方式的不同,产生了不同的类型(exchange_type) - direct - fanout 广播模式 - headers - topic 通配模式 fanout模式下,队列可以随机生成,每个队列对应一个消费者,交换机和队列要进行绑定,但是不指定路由key,保证交换机可以给每个队列都进行广播,如下图所示: ![bindings](./images/bindings.png) fanout模式: ![fanout](./images/python-three-overall.png) ### RabbitMQ之Routing 指定路由,可以实现给指定的队列发送消息。可以通过exchange_type为direct实现。 在direct模式下,交换机和队列进行绑定,而且还要指定路由key,这样就可以让消息发送到指定队列。 ```python channel.queue_bind(exchange=exchange_name, queue=queue_name, routing_key='black') ``` direct模式: ![direct](./images/direct-exchange.png) 在上图的绑定下,routing_key为`orange`将会被exchange转发到`Q1`,routing_key为`black`和`green`将会被exchange转发到`Q2`,所有其他消息将会直接被丢弃。 一个routing_key可以和多个队列进行绑定,如下图所示: ![direct-exchange-multiple](./images/direct-exchange-multiple.png) 通过同一个routing_key绑定所有队列,就是扮演了fanout模式了。 代码中演示的队列示意图如下: ![python-four](./images/python-four.png) ### RabbitMQ之Topic 指定路由,除了direct模式,还可以用topic模式,这种模式更强大一些。提供了通配符机制,可以实现多条件路由。 topic模式下的routing_key必须是“.”号连接的关键词,比如"stock.usd.nyse","nyse.vmw","quick.orange.rabbit"。但是总体长度不能超过255字节。 有两种通配符: 1. `*`(星号):匹配一个单词 2. `#`(井号):匹配零个或多个单词 以下图为例进行说明: ![topic-exchange](./images/python-five.png) 我们将要给符合指定描述的动物发送消息。routing_key是由三个单词组成(中间"."号分割), 第一个单词描述速度,第二个单词描述颜色,第三个单词描述物种,即`<速度>.<颜色>.<物种>` 我们建立了三个绑定:Q1绑定了"`*.orange.*`",Q2绑定了"`*.*.rabbit`"和"`lazy.#`" 这三个绑定表示的含义如下: - Q1对所有orange(橙色)的动物感兴趣 - Q2想要接收关于rabbit(兔子)和lazy(懒散)动物的消息 routing_key为“`quick.orange.rabbit`”的消息,将会被转发给Q1和Q2 routing_key为“`lazy.orange.elephant`”的消息,将会被转发给Q1和Q2 routing_key为“`quick.orange.fox`”的消息,将仅仅被转发给Q1 routing_key为“`lazy.brown.fox`”的消息,将仅仅被转发给Q2 routing_key为“`lazy.pink.rabbit`”的消息,尽管它符合Q2的两个匹配,但是也只会转发给Q2一次消息 routing_key为“`orange`”的消息,不会匹配任何队列,直接丢弃 routing_key为“`quick.orange.male.rabbit`”的消息,不会匹配任何队列,直接丢弃 routing_key为“`lazy.orange.male.rabbit`”的消息,匹配Q2的第二个模式,所以只会转发给Q2 > topic模式可以通过通配符,扮演其他模式: > 当队列绑定routing_key为“#”时,相当于可以接受任何routing_key的消息,扮演了fanout模式; > 当队列绑定routing_key没有通配符时,就相当于direct模式了 ### RabbitMQ之RPC 我们需要调用远程服务器上一个计算函数来获取结果,那就需要采用RPC(Remote Procedure Call) 使用RabbitMQ可以搭建一个RPC系统:一个客户端,和一个可以扩展的RPC服务器 不论客户端还是服务器,都要发送消息(生产者)和接受消息(消费者),所以都要有生产者和消费者。 对于客户端,生产者发送消息作为请求,消费者在回调中处理服务器返回的响应消息 对于服务端,生产者发送消息作为响应,消费者在回调中处理客户端发起的请求消息 **回调队列:** 这个是一个用于缓存服务器回调结果的队列,多个回调结果会缓存到该队列中,回调结果被取走, 队列为空就释放,所以这个队列可以由RabbitMQ随机生成。 **RPC队列:** 这个是一个用于保存客户端请求的队列,多个请求会进入该队列,多个客户端请求都会进入该队列, 所以这个是一个具名队列,不需要释放。 **关联id:** 用来标识每个请求,方便处理响应时,只处理对应请求的响应,不会错位,也就是说一对请求/响应, 通过关联id来一一对应。 rpc通信示意图如下: ![rpc](./images/python-six.png)