代码之家  ›  专栏  ›  技术社区  ›  VPfB

为什么asyncio在没有任何消息的情况下引发TimeoutError?

  •  1
  • VPfB  · 技术社区  · 8 年前

    我在这个代码中遇到了一个小麻烦:

    try:
        return await asyncio.wait_for(tcp_command(cmd), timeout=timeout)
    except (OSError, asyncio.TimeoutError) as err:
        print(f"Network problem: {err}")
    

    当超时发生时,它只打印“网络问题:”。它是由附加到所引发的异步IO.TimeoutError:

    # inside wait_for():
    raise futures.TimeoutError()
    

    把这件事搞清楚很容易 TimeoutError

    2 回复  |  直到 8 年前
        1
  •  1
  •   user4815162342    8 年前

    在Python中,异常将提供解释问题的消息的期望不是一般异常契约的一部分。对于系统异常,例如 OSError 程序必须能够获得操作系统提供的错误消息,因为程序没有资格根据代码或异常子类型猜测消息。

    但更基本的语言例外情况并非如此。举个例子, KeyError 抚养人 dict.__getitem__ :

    >>> try:
    ...   d[123]
    ... except KeyError as err:
    ...   print(f"Dict problem: {err}")
    ... 
    Dict problem: 123
    

    从这个意义上说, TimeoutError 更像是 键错误 比喜欢 O错误 . 当你抓住 超时错误 ,你知道发生了什么-暂停。您通常希望根据发生超时的事实来执行某些操作,而不仅仅是向用户显示消息。即使您确实想提供消息,也应该使用对应用程序有意义的消息,而不是Python提供的通用消息。这与 在这里,除了显示来自操作系统的消息之外,您通常不能做任何其他事情,而在这里,该消息对于调查潜在问题是非常宝贵的。

    总而言之,问题是您在同一个数据库中捕获了两个根本不同的异常 except

    try:
        return await asyncio.wait_for(tcp_command(cmd), timeout=timeout)
    except OSError as err:
        print(f"Network problem: {err}")
    except asyncio.TimeoutError:
        print("Operation timed out")
    
        2
  •  3
  •   freakish    8 年前

    有什么好的理由吗?

    是的,你希望收到什么样的信息 TimeoutError ? "“发生超时”?例外本身是不言自明的,不需要这种冗余。

    我的假设——打印一个异常应该给我们一个出错的线索——正确吗?

    有没有线索?对。全部信息?否。异常消息不是必需的。异常的类型也是一个重要的信息。在许多情况下甚至比信息本身更重要。

    所以首先:使用 print 一开始就错了。Python有非常丰富的日志支持。例如 logger.exception(str(exc)) 解决您的问题,因为它除了记录消息外,还记录整个回溯。至少在默认情况下,它可以自定义。

    打印

    import traceback
    # traceback.print_exc()
    print(traceback.format_exc())
    

    # print(f'[{type(exc).__name__}] {exc}')
    print(f'[{type(exc)}] {exc}')
    

    或例外自定义:

    try:
        return await asyncio.wait_for(tcp_command(cmd), timeout=timeout)
    except OSError as err:
        print(f"Network problem: {err}")
    except asyncio.TimeoutError:
        print('Timeout occured')