PyInstaller打包的应用程序在控制台模式下运行良好,在窗口模式下崩溃



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

然而,我手头有一个奇怪的问题。我以前使用过PyInstaller(顺便说一下,使用的是版本2),但从未发生过这种情况

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

当我查看小型转储文件时,出现了一些关于QtGui4.dll文件内存访问违规的错误。同样,在控制台模式下不会发生这种情况。

有人有什么想法吗?

BadFileDescriptor错误以及由此导致的内存访问违规是由于窗口模式下应用程序的stdout是一个固定大小的缓冲区。因此,如果您正在直接使用printsys.stdoutstdout进行写入,那么过一段时间后您会看到这些错误。

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

  1. 删除/注释stdout上的文字
  2. 使用logging而不是打印到stdout
  3. 在应用程序开始执行时重定向stdout。这是一个需要更改较少代码的解决方案,尽管我认为将调试语句移动到logging将是更好的选择

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

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

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

例如,您可以这样做,以便在不更改太多代码的情况下利用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

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

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

最新更新