具有异步功能的Python事件处理程序(无阻塞while循环)

时间:2019-03-13 21:42:55

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

import queue

qq = queue.Queue()
qq.put('hi')

class MyApp():

    def __init__(self, q):
        self._queue = q

    def _process_item(self, item):
        print(f'Processing this item: {item}')

    def get_item(self):
        try:
            item = self._queue.get_nowait()
            self._process_item(item)
        except queue.Empty:
            pass

    async def listen_for_orders(self):  
        '''
        Asynchronously check the orders queue for new incoming orders
        '''
        while True:
            self.get_item()
            await asyncio.sleep(0)      

a = MyApp(qq)

loop = asyncio.get_event_loop()

loop.run_until_complete(a.listen_for_orders())

使用Python 3.6。

我正在尝试编写一个事件处理程序,该事件处理程序将不断侦听queue中的消息并进行处理(在这种情况下将它们打印出来)。但是它必须是异步-我需要能够在终端(IPython)中运行它,并将其手动输入到queue(至少在最初用于测试)。

此代码不起作用-它会永远阻止。

我如何使它永久运行,但在while循环的每次迭代后返回控制权?

谢谢。

旁注: 为了使事件循环与IPython(7.2版)一起使用,我使用了ib_insync库中的this代码,在上面的示例中,我将该库用于实际问题。 / p>

2 个答案:

答案 0 :(得分:2)

这不是异步队列。您需要使用asyncio.Queue

qq = queue.Queue()

异步是一个事件循环。您调用循环传递控件给它,它一直循环直到您的函数完成,这永远不会发生:

loop.run_until_complete(a.listen_for_orders())

您评论了

  

我有另一个线程,该线程轮询外部网络资源以获取数据(I / O密集型),并将传入的消息转储到该线程中。

异步编写该代码-这样您就可以:

async def run():
    while 1:
        item = await get_item_from_network()
        process_item(item)

loop = asyncio.get_event_loop()
loop.run_until_complete( run() )

如果您不想这样做,您可以做的就是遍历循环,尽管您不想这样做。

import asyncio


def run_once(loop):
    loop.call_soon(loop.stop)
    loop.run_forever()


loop = asyncio.get_event_loop()

for x in range(100):
    print(x)
    run_once(loop)

然后,您只需调用异步函数,并且每次调用run_once时,它将检查您的(异步队列),并将控制传递给您的“听订单”函数(如果队列中有项目)。

答案 1 :(得分:2)

您需要将队列设为asyncio.Queue,并以线程安全的方式将内容添加到队列中。例如:

qq = asyncio.Queue()

class MyApp():
    def __init__(self, q):
        self._queue = q

    def _process_item(self, item):
        print(f'Processing this item: {item}')

    async def get_item(self):
        item = await self._queue.get()
        self._process_item(item)

    async def listen_for_orders(self):  
        '''
        Asynchronously check the orders queue for new incoming orders
        '''
        while True:
            await self.get_item()

a = MyApp(qq)

loop = asyncio.get_event_loop()

loop.run_until_complete(a.listen_for_orders())

您的其他线程必须将诸如此类的东西放入队列:

loop.call_soon_threadsafe(qq.put_nowait, <item>)

call_soon_threadsafe将确保正确的锁定,并确保在准备好新的队列项目时唤醒事件循环。

相关问题