我有这段代码来测试Pencio是如何工作的:
stop = False
async def subcoro():
# same result even with a range of 30
for i in range(30000):
pass
async def first():
global stop
while not stop:
await subcoro()
# without sleep no signal is triggered
await asyncio.sleep(0.1)
async def main(loop):
coro = asyncio.ensure_future(first())
await asyncio.wait([coro], loop=loop)
def end():
global stop
stop = True
if __name__ == '__main__':
loop = asyncio.get_event_loop()
for signame in ('SIGINT', 'SIGTERM'):
loop.add_signal_handler(getattr(signal, signame), end)
try:
loop.run_until_complete(asyncio.ensure_future(main(loop)))
finally:
loop.close()
print('Bye!')
为什么我必须让first()
休眠一段时间(甚至小于0.1)才能让程序处理信号?有没有其他方法可以优雅地关闭所有协程和事件循环?
更新:在python-forum.org上,他们告诉我在PEP-0492上阅读,但没有提供任何解决方案或建议。
客户2:我的真实的应用程序:https://github.com/FedericoTorsello/Embedded/tree/serialIO
2条答案
按热度按时间zsbz8rwp1#
我喜欢这个问题,我尝试的第一件事是
strace
都:对于
sleep
,我看到了很多epoll
(等待信号,通过套接字“转发”,通常是为了遵守处理接收信号所需的原子性)。如果没有
sleep
,就没有epoll
,所以信号被进程接收,信息被推到套接字上,但永远不会读取。为什么会这样?从语义学的Angular 来看,
是“牢不可破”的,
await
类似于yield from
,挂起[the]协程的执行,直到[the] awaitable完成并返回结果数据。但是由于您的
subcoro
没有给予循环,它将“立即”返回,因此“await”得到满足,循环再次循环,永远不会给主循环追赶的机会。所以你真的在一个“无限的while循环”中,永远不会把手还给主循环。
现在,使用
asyncio.sleep
,您可以将手交还给主循环,因为很明显,asyncio.sleep
的实现可以做到这一点,因此主循环可以在睡眠期间做其他事情,例如检查网络事件,例如套接字上接收的信号。还有另一种方式来显式地将手给予循环,是一个空的“yield”,比如:现在,调用
await cooperate()
与不实际休眠的await asyncio.sleep(0.1)
具有相同的效果,这是asyncio.sleep
在给定0
延迟时的情况:从实施的Angular 来看,现在:
在sleep中,
asyncio.base_events.BaseEventLoop._run_once
会被反复调用,但在没有sleep
的情况下永远不会返回,可能是因为你的first
永远不会返回它,我没有深入检查它。总结如下:
subcoro
按原样是没有意义的,在真实的世界应用中,它会给主循环回给予一些时间,通常是通过调用网络,或者等待任何东西。n1bvdmb62#
Since loop. add.. sig调用的函数/处理程序可以在信号处理期间与循环交互(不需要显式地传递它或其他参数,如seen doc)。按照lib aiohttp/gunicorn eg,在所有coros
except CustmException:
子句中引发CustomException()并清理。范例: