从不同事件循环中取消Python Asyncio任务

时间:2019-06-06 08:17:10

标签: python asynchronous async-await python-asyncio

我认为我遇到的问题与事件循环有关,并从与事件循环不同的地方调用cancel。我认为引起该问题的代码是传递给客户端库的同步方法连接到外部源时,当外部源失去连接时,它将调用此方法。

然后的问题是,stop和start方法都是异步的,并且在它们自己的工作上都可以正常运行,start方法是在任务中创建的,它等待睡眠结束,然后调用stop来取消任务,并且看起来可以正常工作,从sync方法中,我需要创建一个新的事件循环来调用stop,它也可以工作,但是虽然可以调用cancel,但任务似乎从未关闭,并且只有在睡眠完成后才能得到重新连接的预期结果。如果在变量之前和之后打印self._task变量,则表明它已被取消,但显然仍在运行。

<Task pending coro=<AsyncAKSServer.start() running at aks_server.py:88> wait_for=<Future pending cb=[<TaskWakeupMethWrapper object at 0x7f551e268f18>()]> cb=[<TaskWakeupMethWrapper object at 0x7f551e268e58>()]>
<Task pending coro=<AsyncAKSServer.start() running at aks_server.py:88> wait_for=<Future cancelled> cb=[<TaskWakeupMethWrapper object at 0x7f551e268e58>()]>

不幸的是,由于IP的原因,我无法提供确切的代码,但是下面的示例显示了我正在尝试执行的操作,由于我们在外,我无法更新当前已将同步方法发送到的客户端库忙碌期间,因此无法将其更改为异步。我确实有可能误解了文档,应该对它的工作有所帮助。

import asyncio

class AsyncServer:
    def __init__(self):
        self._task = None
        self._duration = 1

    async def run(self):
        while True:
            self._task = asyncio.create_task(self.start())
            try:
                await self._task
            except asyncio.CancelledError:
                print('Start task cancelled')

    async def start(self):
        await asyncio.sleep(self._duration)
        await self.stop()

    async def stop(self):
        self._taks.cancel()

    def sync_request(self):
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop.run_until_complete(self.stop())
        loop.stop()
        loop.close()

def main():
    server = AsyncServer()
    asyncio.run(server.run())

1 个答案:

答案 0 :(得分:0)

此问题确实是由必须创建一个新的事件循环引起的,其解决方法是在启动方法中存储对事件循环的引用。然后,您可以使用它来调用asyncio.run_coroutine_threadsafe(self.stop(), self._loop),该循环将传递相同的循环,并使取消操作按预期进行。