检测一个空闲的asyncio事件循环

是否有一些编程模式,使我能够检测到什么时候asyncio事件循环在以下意义上变为空闲? 假设我的执行路径以某种复杂的方式分支,比如使用asyncio.gather(),但我知道每个分支最终都会等待一些空闲的协程,比如套接字或子进程。 说我知道这些协程实际上从来没有屈服,所以事件循环会执行任何python代码,但最终只会等待那些空闲的协程。 有没有一种编程方式来检测这种状态并停止循环?


你所说的“空闲”可能更准确地描述为“等待IO或超时”。 在正确编写的asyncio代码中,不应该检测到循环处于该状态,因为它应该不重要 - 循环正在完成它的工作,取决于诸如asyncio.gatherasyncio.waitloop.run_until_complete确保它在适当的时候结束。 然而,事情并不总是完美的,如果你真的想这样做,这当然是可能的。

在事件循环的每一步,它都会检查准备运行的任务。 如果有,他们的步骤被调用。 一旦没有更多任务准备好,事件循环会等待IO事件或最早的超时,以先发生者为准。 需要注意的重要一点是运行任务总是优先于等待IO。 因此,要检测没有任务准备好的情况,可以安排一个已知立即触发的虚拟IO事件。

以下协程创建了这样一个事件并等待它触发:

import socket, asyncio

async def detect_iowait():
    loop = asyncio.get_event_loop()
    rsock, wsock = socket.socketpair()
    wsock.close()
    await loop.sock_recv(rsock, 1)
    rsock.close()

它建立一个套接字对,从一个套接字读取返回写入其他套接字的数据。 它立即关闭其中一个套接字,以便从另一个套接字读取立即返回EOF,表示为空字节阵列。 等待来自该套接字的读取基本上是非阻塞的 - 但asyncio不知道,因此它将套接字放置在IO等待列表中。 如上所述,只要不存在可运行任务,asyncio将等待IO,并且detect_iowait将等待套接字读取并退出。 因此等待detect_iowait()本身检测到IO等待。

使用detect_iowait()测试代码可能如下所示:

# stop loop.run_forever once iowait is detected
async def stop_on_iowait():
    await detect_iowait()
    print('iowait detected, stopping!')
    asyncio.get_event_loop().stop()

# a dummy calculation coroutine, emulating your execution path
async def calc(n):
    print('calc %d start' % n)
    async def noop():
        pass
    for i in range(n):
        await noop()
    print('calc %d end' % n)

# coroutine that waits on IO forever, also (ab)using a socket pair,
# this time creating a socket whose recv will never complete
async def io_forever():
    loop = asyncio.get_event_loop()
    sock, _ = socket.socketpair()
    sock.setblocking(False)
    await loop.sock_recv(sock, 1)

loop = asyncio.get_event_loop()
for t in calc(1000), calc(10000), calc(100000), io_forever():
    loop.create_task(t)
loop.create_task(stop_on_iowait())
loop.run_forever()
链接地址: http://www.djcxy.com/p/53217.html

上一篇: Detect an idle asyncio event loop

下一篇: Is there a way to manually switch on asyncio event loop