2012-11-17 92 views
3

我正在使用Python和PySide構建一個相當複雜的應用程序。最後,發佈日期即將到來,所以我想將這個應用程序構建爲一個exe文件。PyInstaller打包的應用程序在控制檯模式下工作正常,在窗口模式下崩潰

但是,我手上有一個奇怪的問題。我已經在過去使用過PyInstaller(使用版本2),從來沒有發生過這種事情。

基本上,當我使用--console標誌構建應用程序時,它可以正常工作 - 但它會打開控制檯窗口。當我用窗口標誌(-w)構建應用程序時,它不能正常工作。它始於一切,但所有這些奇怪的故障。例如,加載文本文件通常會引發BadFileDescriptor錯誤(在控制檯模式下不會發生這種錯誤),並且在執行特定任務後應用程序崩潰。更糟糕的是,這個任務是一個循環,並且它在第一次時表現良好,但是當它再次開始工作時,它會崩潰。

當我看着minidump文件時,出現了一些關於QtGui4.dll文件內存訪問衝突的錯誤。再次,這在控制檯模式下不會發生。

任何人有任何想法?

+2

請問您的程序中使用'print'陳述或者'sys.stdout.write'?閱讀[這裏](https://groups.google.com/forum/?fromgroups=#!topic/it.comp.lang.python/3770608EYPc)(意大利語對你不幸),錯誤的文件描述符錯誤可能是由於,你可以解決它刪除/註釋'print's或重定向'sys.stdout'或使用'logging'來代替。 看來,當你以窗口模式啓動應用程序時,它的'stdout'是一個固定大小的緩衝區,這會導致內存訪問衝突。 – Bakuriu

+0

它確實使用打印語句。你能告訴我更多關於如何重定向sys.stdout嗎?我的意思是,是否可以用一行代碼輕鬆替換軟件中的所有打印語句? –

+1

你可以放置類似'import sys;導入tempfile; sys.stdout = tempfile.TemporaryFile(); sys.stderr = tempfile.TemporaryFile()'(希望有更好的格式化)在程序執行的最初階段,所有'print's將被重定向到一個臨時文件,當你的程序退出時它將被刪除。對於更長期的解決方案,我會考慮使用'logging'。 – Bakuriu

回答

5

BadFileDescriptor錯誤和相應的內存訪問衝突是由窗口模式下的應用程序的stdout是固定大小的緩衝區引起的。 因此,如果您直接致電stdout,或者直接與printsys.stdout聯繫,那麼經過一段時間後,您會看到這些錯誤。

你可以解決這個問題:

  1. 刪除/上stdout
  2. 註釋掉的著作使用logging,而不是打印到stdout
  3. 在應用程序的開始執行重定向stdout。這是需要更少代碼的解決方案,儘管我認爲將調試語句移到logging將是更好的選擇。只是執行程序之前

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

重定向stdout你可以使用這種代碼。你也可以使用一些自定義對象將輸出放在「日誌」文件或其他內容中,重要的是輸出不應該填充固定大小的緩衝區。

例如,你可以做這樣的事情,以便能夠利用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,以避免錯誤。)

+0

使用多處理的第二種方法,它抱怨flush()丟失 - 我不得不向debug_logger添加一個dummy(僅包含'pass')flush例程。 – Andris

+0

@Andris編輯包含它,只是爲了安全。 – Bakuriu

+0

在現代Windows上,有時Windows只會「暫停」進程,等待stdout被清空,導致程序無聲無息地失敗。嘆。 –

相關問題