Asyncio和rabbitmq(asynqp):如何同时使用多个队列

时间:2016-08-11 12:04:07

标签: python python-3.x rabbitmq python-asyncio aiohttp

我尝试使用python,asyncio和asynqp同时使用多个队列。

我不明白为什么我的asyncio.sleep()函数调用没有任何效果。代码不会在那里暂停。公平地说,我实际上并不了解回调执行的上下文,以及我是否可以完全控制bavck到事件循环(这样asyncio.sleep()调用才有意义。)

如果我必须在aiohttp.ClientSession.get()回调函数中使用process_msg函数调用,该怎么办?我不能这样做,因为它不是协程。必须有一种方法超出我目前对asyncio的理解。

#!/usr/bin/env python3

import asyncio
import asynqp


USERS = {'betty', 'bob', 'luis', 'tony'}


def process_msg(msg):
    asyncio.sleep(10)
    print('>> {}'.format(msg.body))
    msg.ack()

async def connect():
    connection = await asynqp.connect(host='dev_queue', virtual_host='asynqp_test')
    channel = await connection.open_channel()
    exchange = await channel.declare_exchange('inboxes', 'direct')

    # we have 10 users. Set up a queue for each of them
    # use different channels to avoid any interference
    # during message consumption, just in case.
    for username in USERS:
        user_channel = await connection.open_channel()
        queue = await user_channel.declare_queue('Inbox_{}'.format(username))
        await queue.bind(exchange, routing_key=username)
        await queue.consume(process_msg)

    # deliver 10 messages to each user
    for username in USERS:
        for msg_idx in range(10):
            msg = asynqp.Message('Msg #{} for {}'.format(msg_idx, username))
            exchange.publish(msg, routing_key=username)


loop = asyncio.get_event_loop()
loop.run_until_complete(connect())
loop.run_forever()

2 个答案:

答案 0 :(得分:2)

  

我不明白为什么我的asyncio.sleep()函数调用没有   任何影响。

因为asyncio.sleep()返回一个必须与事件循环(或async/await语义)结合使用的未来对象。

您无法在简单await声明中使用def,因为回调是在async/await上下文之外调用的,该回调附加到引擎盖下的某个事件循环中。换句话说,将回调样式与async/await样式混合起来非常棘手。

简单的解决方案是将工作安排回事件循环:

async def process_msg(msg):
    await asyncio.sleep(10)
    print('>> {}'.format(msg.body))
    msg.ack()

def _process_msg(msg):
    loop = asyncio.get_event_loop()
    loop.create_task(process_msg(msg))
    # or if loop is always the same one single line is enough
    # asyncio.ensure_future(process_msg(msg))

# some code
await queue.consume(_process_msg)

请注意,_process_msg函数中没有递归,即在process_msg中未执行_process_msg的正文。一旦控件返回事件循环,将调用内部process_msg函数。

这可以通过以下代码进行推广:

def async_to_callback(coro):
    def callback(*args, **kwargs):
        asyncio.ensure_future(coro(*args, **kwargs))
    return callback

async def process_msg(msg):
    # the body

# some code
await queue.consume(async_to_callback(process_msg))

答案 1 :(得分:1)

请参阅github上的Drizzt1991's response以获得解决方案。