当前位置: 首页 > 面试题库 >

如何消除“ sys.excepthook丢失”错误?

伍耀
2023-03-14
问题内容

注意:我没有尝试在Windows或2.7.3以外的Python版本下重现下面描述的问题。

引发问题的最可靠方法是通过:(在之下bash)通过管道传递以下测试脚本的输出:

try:
    for n in range(20):
        print n
except:
    pass

即:

% python testscript.py | :
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr

我的问题是:

__如图所示(在Unix /下bash)运行脚本时, 如何修改上面的测试脚本 以避免错误消息?

(如测试脚本所示,不能用来捕获错误try-except。)

诚然,上面的示例是高度人为的,但是当我的脚本的输出通过某些第三方软件传递时, 有时会 遇到相同的问题。

该错误消息当然是无害的,但是它使最终用户感到不安,因此我想使其静音。

编辑:以下脚本与上面的原始脚本有所不同,仅在于它重新定义了sys.excepthook,其行为与上面给出的完全相同。

import sys
STDERR = sys.stderr
def excepthook(*args):
    print >> STDERR, 'caught'
    print >> STDERR, args

sys.excepthook = excepthook

try:
    for n in range(20):
        print n
except:
    pass

问题答案:

如图所示(在Unix /下bash)运行脚本时,如何修改上面的测试脚本以避免错误消息?

您将需要防止脚本将任何内容写入标准输出。这意味着删除所有print语句和对的任何使用sys.stdout.write以及调用这些语句的任何代码。

发生这种情况的原因是,您正在将来自Python脚本的非零数量的输出传递给从未从标准输入读取的内容。这不是该:命令独有的。您可以通过管道传输到任何不读取标准输入的命令来获得相同的结果,例如

python testscript.py | cd .

再举一个简单的例子,考虑一个脚本,printer.py其中只包含

print 'abcde'

然后

python printer.py | python printer.py

会产生相同的错误。

当将一个程序的输出通过管道传输到另一个程序时,写入程序产生的输出将备份到缓冲区中,并等待读取程序从缓冲区中请求该数据。只要缓冲区是非空的,任何试图关闭写入文件对象的尝试都将因错误而失败。这是您看到的消息的根本原因。

触发错误的特定代码在Python的C语言实现中,这说明了为什么无法使用try/except块捕获该错误:它在脚本内容完成处理后运行。基本上,当Python关闭自身时,它会尝试关闭stdout,但这失败了,因为仍然有缓冲的输出等待读取。因此,Python会尝试像往常一样报告此错误,但sys.excepthook已在完成过程中被删除,因此失败。然后,Python尝试将消息打印到sys.stderr,但该消息已被重新分配,因此再次失败。您在屏幕上看到消息的原因是Python代码确实包含偶然性fprintf
即使Python的输出对象不存在,也可以直接将一些输出写到文件指针中。

对于那些对此过程的细节感兴趣的人,让我们看一下Python解释器的关闭序列,该序列是通过Py_Finalize函数来实现的pythonrun.c

  1. 调用出口挂钩并关闭线程后,完成代码将调用PyImport_Cleanup以完成和取消分配所有导入的模块。此函数执行的倒数第二个任务是删除sys模块,该模块主要包括调用_PyModule_Clear以清除模块字典中的所有条目-特别是包括标准流对象(Python对象)stdoutstderr
  2. 当值是从字典移除或由一个新的值代替,其引用计数被递减使用的Py_DECREF宏。引用计数达到零的对象有资格进行释放。由于sys模块保留了对标准流对象的最后剩余引用,因此当这些引用未设置时_PyModule_Clear,就可以将其释放。1个
  3. Python文件对象的重新分配由实现的file_dealloc功能在fileobject.c。首先使用适当命名的函数调用Python文件对象的close方法close_the_file
    ret = close_the_file(f);
    

对于标准文件对象,close_the_file(f)
委托给Cfclose函数,如果仍有数据要写入文件指针,则C函数设置错误条件。file_dealloc然后检查该错误情况并打印您看到的第一条消息:

    if (!ret) {
    PySys_WriteStderr("close failed in file object destructor:\n");
    PyErr_Print();
}
else {
    Py_DECREF(ret);
}
  1. 打印该消息后,Python然后尝试使用显示异常PyErr_Print。委托PyErr_PrintEx并作为其功能的一部分,PyErr_PrintEx尝试从访问Python异常打印机sys.excepthook
    hook = PySys_GetObject("excepthook");
    

如果在Python程序的正常过程中这样做会很好,但是在这种情况下,sys.excepthook已经清除了。2
Python检查此错误情况,并输出第二条消息作为通知。

    if (hook && hook != Py_None) {
    ...
} else {
    PySys_WriteStderr("sys.excepthook is missing\n");
    PyErr_Display(exception, v, tb);
}
  1. 在通知我们有关丢失的信息之后excepthook,Python然后回退到使用来打印异常信息PyErr_Display,这是显示堆栈跟踪的默认方法。此功能所做的第一件事就是尝试访问sys.stderr
    PyObject *f = PySys_GetObject("stderr");
    

在这种情况下,这将不起作用,因为sys.stderr它已被清除并且无法访问。3因此,代码fprintf直接调用以将第三条消息发送到C标准错误流。

    if (f == NULL || f == Py_None)
    fprintf(stderr, "lost sys.stderr\n");

有趣的是,此行为在Python
3.4+中有所不同,因为完成过程现在在清除内置模块之前会显式刷新标准输出和错误流。这样,如果您有等待写入的数据,则将得到一个错误信号,该信号明确地表明该情况,而不是正常完成过程中的“偶然”故障。另外,如果您跑步

python printer.py | python printer.py

使用Python
3.4(print当然在语句后加上括号),您根本不会遇到任何错误。我想第二次调用Python可能出于某种原因消耗了标准输入,但这是一个完全独立的问题。

1实际上,这是一个谎言。Python的导入机制缓存每个导入模块的字典中的副本,这是不释放,直到_PyImport_Fini运行,后来在执行Py_Finalize,并且
那是 什么时候的标准流对象的最后一个引用消失。一旦引用计数达到零,
就立即Py_DECREF释放对象。但是,对于主要答案而言,最重要的是将引用从模块的字典中删除,然后在以后的某个时间释放。 __sys

2同样,这是因为sys借助属性缓存机制,在真正释放任何内容之前,该模块的字典已被完全清除。您可以运行Python,并带有-vv选项以查看所有模块的属性都未设置,然后获得有关关闭文件指针的错误消息。

3除非您了解前面脚注中提到的属性缓存机制,否则这部分行为是唯一没有意义的部分。



 类似资料:
  • 本文向大家介绍kafka如何保证不丢失消息?相关面试题,主要包含被问及kafka如何保证不丢失消息?时的应答技巧和注意事项,需要的朋友参考一下 复制因子:创建topic的时候指定复制因子大于1时,一个分区被分配到一个broker上,同时会在其他broker上维护一个分区副本; isr列表:分区及其副本分别为leader和follower,leader对外提供读写服务,follower会向leade

  • 主要内容:文章目录,1.RocketMQ,2.Kafka,3.如何保证RabbitMQ全链路数据100%不丢失mq: rabbitmq, rocketmq, kafka 文章目录 1.RocketMQ 2.Kafka 2.1 消息传递语义剖析 2.2 Producer 端丢失场景剖析 2.3 Broker 端丢失场景剖析 2.4 Consumer 端丢失场景剖析 3.如何保证RabbitMQ全链路数据100%不丢失 3.1 生产端可靠性投递 3.2 消费端消息不丢失 1.RocketMQ Roc

  • 主要内容:一、业务场景,二、意外宕机,问题凸现,三、总结一、业务场景 这篇文章,我们来看看订单服务和消息服务是如何基于MQ来收发消息的。 我们稍微把这个图细化一点,简单来说就是多个订单服务实例给queue推送消息,多个仓储服务每个消费一部分消息。如下图所示: 二、意外宕机,问题凸现 假如你线上对MQ技术的使用就到此为止了,那么基本可以跟offer说拜拜了。。。 因为如果是我的话,作为一个面试官就没法继续往下问了。你这个MQ的使用以及理解的深度仅此而已的

  • 我正在使用spring data redis运行Spring Boot服务,下面是以下配置。 该服务似乎可以工作,但我在日志中看到了一条丢失哨兵消息流。哨兵节点可从运行服务的VM中访问。我能够直接从那个虚拟机对他们进行telnet。知道为什么会这样吗?

  • 主要内容:一、背景引入,二、前情回顾,三、目前已有的技术方案,四、数据100%不丢失了吗?,五、按需制定技术方案,六、需要研究的技术细节一、背景引入 这篇文章,我们来聊聊在线上生产环境使用消息中间件技术的时候,从前到后的全链路到底如何保证数据不能丢失。 这个问题,在互联网公司面试的时候高频出现,而且也是非常现实的生产环境问题。 如果你的简历中写了自己熟悉MQ技术(RabbitMQ、RocketMQ、Kafka),而且在项目里有使用的经验,那么非常实际的一个生产环境问题就是:投递消息到MQ,然后从

  • 主要内容:一、背景引入,二、目前已有的技术方案,三、数据100%不丢失了吗?,四、按需制定技术方案一、背景引入 这篇文章,我们来聊聊在线上生产环境使用消息中间件技术的时候,从前到后的全链路到底如何保证数据不能丢失。 这个问题,在互联网公司面试的时候高频出现,而且也是非常现实的生产环境问题。 如果你的简历中写了自己熟悉MQ技术(RabbitMQ、RocketMQ、Kafka),而且在项目里有使用的经验,那么非常实际的一个生产环境问题就是:投递消息到MQ,然后从MQ消费消息来处理的这个过程,数据到