中断当前正在执行的所有asyncio.sleep

时间:2016-05-13 12:17:10

标签: python linux async-await python-asyncio

其中

这是在Linux,Python 3.5.1上。

什么

我正在开发一个asyncio的监控流程,其await位于asyncio.sleep不同时段的asyncio.sleep来电。

我希望能够中断所有def sigalrm_sent(signum, frame): tse.logger.info("got SIGALRM") signal.signal(signal.SIGALRM, sigalrm_sent) 次呼叫并让所有任务正常进行,但我找不到如何做到这一点。一个例子是正常关闭监视器进程。

如何(失败的假设)

我认为我可以发送一个ALRM信号,但过程就会消失。我尝试用以下方法捕获ALRM信号:

asyncio.sleep

然后我得到关于捕获SIGALRM的日志行,但asyncio.sleep调用不会中断。

如何(kludge)

此时,我通过调用此协程替换了所有async def interruptible_sleep(seconds): while seconds > 0 and not tse.stop_requested: duration = min(seconds, tse.TIME_QUANTUM) await asyncio.sleep(duration) seconds -= duration 次调用:

TIME_QUANTUM

所以我只需选择一个不太小而且不太大的asyncio.sleep

有没有办法打断所有正在运行的Promise.all()来电,而我却错过了?

2 个答案:

答案 0 :(得分:5)

中断asyncio.sleep的所有正在运行的调用似乎有点危险,因为它可以在代码的其他部分中用于其他目的。相反,我会制作一个专用的sleep协程来跟踪其正在运行的呼叫。然后可以通过取消相应的任务来中断它们:

def make_sleep():
    async def sleep(delay, result=None, *, loop=None):
        coro = asyncio.sleep(delay, result=result, loop=loop)
        task = asyncio.ensure_future(coro)
        sleep.tasks.add(task)
        try:
            return await task
        except asyncio.CancelledError:
            return result
        finally:
            sleep.tasks.remove(task)

    sleep.tasks = set()
    sleep.cancel_all = lambda: sum(task.cancel() for task in sleep.tasks)
    return sleep

示例:

async def main(sleep, loop):
    for i in range(10):
        loop.create_task(sleep(i))
    await sleep(3)
    nb_cancelled = sleep.cancel_all()
    await asyncio.wait(sleep.tasks)
    return nb_cancelled

sleep = make_sleep()
loop = asyncio.get_event_loop()
result = loop.run_until_complete(main(sleep, loop)) 
print(result)  # Print '6'

出于调试目的,loop.time = lambda: float('inf')也可以。

答案 1 :(得分:1)

根据Vincent的回答,我使用了以下类(该类的每个实例都可以取消所有正在运行的.sleep任务,从而实现更好的分区化):

class Sleeper:
    "Group sleep calls allowing instant cancellation of all"

    def __init__(self, loop):
        self.loop = loop
        self.tasks = set()

    async def sleep(self, delay, result=None):
        coro = aio.sleep(delay, result=result, loop=self.loop)
        task = aio.ensure_future(coro)
        self.tasks.add(task)
        try:
            return await task
        except aio.CancelledError:
            return result
        finally:
            self.tasks.remove(task)

    def cancel_all_helper(self):
        "Cancel all pending sleep tasks"
        cancelled = set()
        for task in self.tasks:
            if task.cancel():
                cancelled.add(task)
        return cancelled

    async def cancel_all(self):
        "Coroutine cancelling tasks"
        cancelled = self.cancel_all_helper()
        await aio.wait(self.tasks)
        self.tasks -= cancelled
        return len(cancelled)