我在循环中接收消息,我希望循环是可取消的,所以我使用asyncio.Event
对象作为循环何时退出的标志,如下所示:
class MyThing:
def __init__(self):
self.quit = asyncio.Event
async def loop(self):
while True:
t1 = self.quit.Wait()
t2 = self.recv_message()
done, pending = asyncio.wait([t1, t2], return_when=asyncio.FIRST_COMPLETED)
if t1 in done:
break
问题是t1 in done
返回False
,即使t1
在done
中也是如此。在if
语句之前粘贴一个断点,我可以看到t1
如下所示:
(Pdb) p t1
<coroutine object Event.wait at 0x7fcff72ed340>
但是done
看起来是这样的:
{<Task finished name='Task-95' coro=<Event.wait() done, defined at /usr/lib64/python3.8/asyncio/locks.py:296> result=True>}
当然,有很多方法可以解决这个问题。我可以写:
if t2 not in done:
这似乎是正确的。我也可以检查一下self.quit.is_set()
。但是为什么这个t1 in done
测试不能像我预期的那样工作呢?
发布于 2020-11-13 13:21:48
但是为什么这个
t1 in done
测试不能像我预期的那样工作呢?
因为asyncio.wait
接受任何类型的可访问对象,那些使用await
关键字工作的对象,尤其是通过调用async def
获得的对象。它返回的对象是asyncio.Future
的子类,尤其是Task
实例的子类。期货可以在后台运行,并支持一系列启用wait
的方法,如add_done_callback
、result
等。
asyncio.wait
对它所接收的服务对象所做的第一件事是使用asyncio.ensure_future
将它们转换为期货,这会将协同任务对象转换为任务,而通常,其他可服务性对象将转换为适当类型的未来。从那时起,它与期货一起工作,并归还它们。这种混乱甚至在文档中被描述,甚至促使开发人员放弃将非期货传递给asyncio.wait
。
使t1 in done
能够工作的解决方法是让您调用ensure_future
(或者当您知道自己正在处理协同机制时调用create_task
):
t1 = asyncio.ensure_future(self.quit.Wait())
t2 = asyncio.ensure_future(self.recv_message())
另外,您不需要事件使循环可取消,您可以使用取消:
class MyThing:
def __init__(self):
# cancel the loop_task with self.loop_task.cancel()
self.loop_task = None
async def loop(self):
self.loop_task = asyncio.create_task(self._loop())
await self.loop_task
async def _loop(self):
while True:
await self.recv_message()
https://stackoverflow.com/questions/64821095
复制相似问题