python之rabbitMQ四:双向生产、消费模式--RPC远程调用
在前面三节中,生产者只作为消息发送方,消费者只作为消息接收方。
假设生产者为客户端向队列中发送消息,服务器为消费者从队列中接收消息;
现在的需求时,生产者在发消息时,要求接收到服务器的返回结果,怎么办?
如果服务器将结果放在同一个队列中,那么在同一队列中既发送又接收消息,将形成死循环。
即在同一个队列中,任何一端都不能既作为生产者又作为消息者,只能选择一方,否则就是死循环。
解决办法:重新声明一个队列,来存放服务器返的结果;此时服务器作为生产者,客户端作为消费者。
这个过程,也称为RPC,Remote Producre Call远程过程调用。

但是,如果服务器不知道将任务结果放在哪个队列,客户端也不知道从哪个队列去取结果,怎么办?
解决办法:客户端在发送消息时,带上一个标记,如参数reply_to=任务结果的队列名称
假设,同一个客户端向任务器发送了三个耗时任务,要求服务器异步返回,在返回结果之前客户端可以做其它事,不需要一直等待。
解决办法:同上,除了为此客户端添加一个任务结果的队列标记外;
但是还需要分别为每个任务再加上一个新的标识符(消息区分),且实现异步返回。
即要求实现双生产、消费模式。如,客户端作为发送方发送任务,又作为接收方接收任务结果;
服务器既作为接收方接收任务,又作为发送方发送任务结果。 这就是RPC。
示例:
客户端:
import pika import uuid class FibonacciRpcClient(object): def __init__(self): self.connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) self.channel = self.connection.channel() # 生成一个随机queue作为任务结果的queue result = self.channel.queue_declare(exclusive=True) self.callback_queue = result.method.queue # 作为接收端,准备接收任务结果 self.channel.basic_consume(self.on_response, no_ack=True, queue=self.callback_queue) def on_response(self, ch, method, props, body): # 作为接收方的callback函数 if self.corr_id == props.correlation_id: self.response = body def call(self, n): self.response = None self.corr_id = str(uuid.uuid4()) # 唯一标识符 # 作为发送者:发送消息及唯一标识符 self.channel.basic_publish(exchange='', routing_key='rpc_queue', properties=pika.BasicProperties( reply_to=self.callback_queue, correlation_id=self.corr_id, ), body=str(n)) count = 0 while self.response is None: # 作为接收方,检查队列中,有没有新消息,但不会阻塞即异步 self.connection.process_data_events() count += 1 print("check....", count) return int(self.response) fibonacci_rpc = FibonacciRpcClient() print(" [x] Requesting fib(30)") response = fibonacci_rpc.call(30) print(" [.] Got %r" % response)
服务器:
import pika connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) channel = connection.channel() channel.queue_declare(queue='rpc_queue') def fib(n): if n == 0: return 0 elif n == 1: return 1 else: return fib(n - 1) + fib(n - 2) def on_request(ch, method, props, body): n = int(body) print(" [.] fib(%s)" % n) response = fib(n) # 作为发送方,发送消息 ch.basic_publish(exchange='', routing_key=props.reply_to, properties=pika.BasicProperties(correlation_id= \ props.correlation_id), body=str(response)) ch.basic_ack(delivery_tag=method.delivery_tag) # 公平分发:一次只接收prefetch_count个消息 channel.basic_qos(prefetch_count=1) # 作为接收方,消费消息 channel.basic_consume(on_request, queue='rpc_queue') print(" [x] Awaiting RPC requests") channel.start_consuming()
参考:
http://www.cnblogs.com/alex3714/articles/5248247.html
celery连接rabbitMQ
https://www.jianshu.com/p/42b98f5eacb3
https://blog.csdn.net/vbirdbest/article/category/7296570
posted on 2019-01-30 21:33 myworldworld 阅读(680) 评论(0) 收藏 举报
浙公网安备 33010602011771号