基本上我想要:
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/