【问题标题】:How to handle error raise - Asyncio in Python3如何处理错误引发 - Python3 中的 Asyncio
【发布时间】:2019-01-03 12:41:53
【问题描述】:

我有一个函数f() 进行 API 调用,我想异步调用它多次。我像这样使用asyncio lib:

async def main():
    loop = asyncio.get_event_loop()
    futures = [loop.run_in_executor(None, f) for i in range(10)]
    await asyncio.gather(*futures)
    return futures

result = asyncio.get_event_loop().run_until_complete(main())

问题是有时f() 会引发Exception,我不知道如何处理它。文档说Futures 可以包含Exception,但这里不是这样,会引发错误并导致程序崩溃。

我如何做到这一点?我想我可以为 f()try: catch: 编写一个包装器,但如果该功能是由 lib 提供的,那似乎很难看。

提前感谢您的帮助,

【问题讨论】:

    标签: python python-asyncio


    【解决方案1】:

    问题是有时f() 会引发Exception 而我不知道如何处理它。

    这取决于您在发生异常时要执行的操作。请记住,asyncio.gather() 是默认传播异常的便利 API,以避免在出现错误时盲目继续。如果您想要在异常情况下继续,您还有其他选择:

    • return_exceptions=True 传递给gather - 这将导致gather 返回异常对象以及其他结果。方便好用,但是把异常和常规结果混在一起,有点乱。

    • 使用asyncio.wait() 代替asyncio.gather()。它返回一组 futures,您可以测试每一个是通过引发还是通过产生结果来完成的。

    • f() 包装在您认为合适的捕获异常的您自己的函数中。您考虑并拒绝了这一点,但在某些情况下,这正是正确的方法。

    【讨论】:

    • 非常感谢您的回答,这正是我想要的。我进行了一些测试,没有清楚地看到前两个选项之间的区别,在我看来 gather(*futures, return_exceptions=True)wait(futures) 做同样的事情(除了 wait 不尊重顺序),在这两种情况下都有例外与结果混合对吗? (这对我的用例来说不是问题,只是为了理解。标记为已解决)
    • @MeanStreet 不同之处在于wait() 返回futures 的集合。给定未来,您可以使用result() 提取其结果,这将返回结果或重新引发异常(如果有)。但是您也可以调用exception() 来测试是否引发了异常。这使您可以区分引发异常的函数和(无论出于何种原因)发生返回 Exception 实例的函数。
    • 哦,我明白了,这就是您所说的“将异常与常规结果混合”的意思。谢谢
    • 您能显示gather 的确切返回值吗?官方文档太差了
    • @Pynchia 如果您询问gather(..., return_exceptions=True),它将返回引发任务的异常对象。例如,给定async def div(n): return 10 / n,表达式await asyncio.gather(*(div(i) for i in range(10)), return_exceptions=True) 将计算为[ZeroDivisionError('division by zero'), 10.0, 5.0, 3.3333333333333335, 2.5, 2.0, 1.6666666666666667, 1.4285714285714286, 1.25, 1.1111111111111112]。如果没有return_exceptions=Trueawait gather(...) 只会引发异常,您将无法观察到成功的结果。
    猜你喜欢
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    • 1970-01-01
    • 2022-12-18
    • 1970-01-01
    • 2020-09-30
    • 2019-02-22
    • 1970-01-01
    相关资源
    最近更新 更多