python - 两次异步操作,一次超时

标签 python python-asyncio

基本上我想要:

await action1()
await action2()
return result

两个操作都有一个超时,并且 - 这很重要 - 有一条错误消息告诉哪个操作超时。

为了比较,只需一个 Action :

try:
    await asyncio.wait_for(action(), timeout=1.0)
except asyncio.TimeoutError:
    raise RuntimeError("Problem")

现在有两个 Action 我有这个但不喜欢它。

import asyncio

async def a2():
    try:
        await asyncio.sleep(1.0)
    except asyncio.CancelledError:
        raise RuntimeError("Problem 1") from None
    try:
        await asyncio.sleep(1.0)
    except asyncio.CancelledError:
        raise RuntimeError("Problem 2") from None
    return True


async def test():
    loop = asyncio.get_event_loop()
    action_task = loop.create_task(a2())
    # timeouts: 0.5 -> Problem1 exc; 1.5 -> Problem2 exc; 2.5 -> OK
    try:
        await asyncio.wait_for(action_task, timeout=0.5)
    except asyncio.TimeoutError:
        pass
    result = await action_task

asyncio.get_event_loop().run_until_complete(test())

我发现它真的违反直觉:

except asyncio.TimeoutError:
     pass

其中超时处理是主要功能。你能推荐一个更好的方法吗?

最佳答案

Can you suggest a better way?

你的代码是正确的,但如果你正在寻找更优雅的东西,也许上下文管理器会适合你的用法:

class Timeout:
    def __init__(self, tmout):
        self.tmout = tmout
        self._timed_out = False
        self._section = None

    async def __aenter__(self):
        loop = asyncio.get_event_loop()
        self._timer = loop.call_later(self.tmout, self._cancel_task,
                                      asyncio.current_task())
        return self

    def set_section(self, section):
        self._section = section

    def _cancel_task(self, task):
        self._timed_out = True
        task.cancel()

    async def __aexit__(self, t, v, tb):
        if self._timed_out:
            assert t is asyncio.CancelledError
            raise RuntimeError(self._section) from None
        else:
            self._timer.cancel()

可以按如下方式使用它:

async def main():
    # raises RuntimeError("second sleep")
    async with Timeout(1) as tmout:
        tmout.set_section("first sleep")
        # increase above 1.0 and "first sleep" is raised
        await asyncio.sleep(0.8)
        tmout.set_section("second sleep")
        await asyncio.sleep(0.5)

asyncio.get_event_loop().run_until_complete(main())

关于python - 两次异步操作,一次超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52498042/

相关文章:

python - Asyncio 错误,尝试对非套接字的对象进行操作

python - 如何在python中处理非常大的文件(13GB)而不会崩溃?

python - 如何更改 OpenCV Python 中轮廓的边界矩形值?

python - 展平包含子列表的列表

postgresql - py.test 混合装置和 asyncio 协程

python - 是否可以从 Python (3.4) 异步查询 SQL Server?

python - 如何调用类中包含的异步函数?

python - 如何让 PyC​​harm 检查 PEP8 代码样式?

python - 如何解压缩字节数组中的 gzip 数据?

Python - 带有 asyncio/coroutine 的定时器