PyInstaller打包的应用程序在控制台模式下工作正常,在窗口模式下崩溃


问题内容

我正在使用Python和PySide构建一个相当复杂的应用程序。终于,发布的日子快到了,所以我想将此应用程序构建为exe。

但是,我手上有一个奇怪的问题。我过去曾经使用过PyInstaller(顺便使用版本2),但从未发生过这种情况。

基本上,当我使用--console标志构建应用程序时,它可以正常工作-
但它会打开控制台窗口。当我使用窗口标志(-w)构建应用程序时,它无法正常工作。它开始了一切,但是所有这些怪异的故障。例如,加载文本文件通常会引发BadFileDescriptor错误(在控制台模式下不会发生),并且执行特定任务后应用程序崩溃。更糟糕的是该任务是一个循环,并且第一次执行良好,但是当它再次开始工作时会崩溃。

当我查看minidump文件时,发现一些有关QtGui4.dll文件的内存访问冲突的错误。同样,在控制台模式下不会发生这种情况。

谁有想法?


问题答案:

BadFileDescriptor误差和因此存储器访问冲突由以下事实引起stdout的在窗口模式下的应用程序是一个固定大小的缓冲区。因此,如果您正在stdout使用printsys.stdout直接写入,一段时间后您会看到这些错误。

您可以通过以下方法解决此问题:

  1. 删除/注释上的著作 stdout
  2. 使用logging而不是打印到标准输出
  3. stdout在应用程序执行开始时进行重定向。尽管我认为将调试语句移至logging将是更好的选择,但这是一种解决方案,只需更改较少的代码。

要重定向,stdout您可以使用以下代码:

import sys
import tempfile
sys.stdout = tempfile.TemporaryFile()
sys.stderr = tempfile.TemporaryFile()

在执行程序之前。您还可以使用一些自定义对象将输出放入“ log”文件或其他文件中,重要的是输出不应填充固定大小的缓冲区。

例如,您可以执行以下操作以在logging不更改太多代码的情况下利用模块:

import sys
import logging

debug_logger = logging.getLogger('debug')
debug_logger.write = debug_logger.debug    #consider all prints as debug information
debug_logger.flush = lambda: None   # this may be called when printing
#debug_logger.setLevel(logging.DEBUG)      #activate debug logger output
sys.stdout = debug_logger

这种方法的缺点是对每一行print执行更多的调用stdout.write

>>> print 'test'
DEBUG:debug:test
DEBUG:debug:

如果愿意,可以避免编写纯write函数the_logger.debug仅用“全行”调用的实际行为。

无论如何,我认为这类解决方案应该只是临时的,并且只能在将prints移植到to的调用之前使用logging.debug

(显然,记录器应写入文件,而不是stdout避免错误。)