2010-03-12 51 views
3

我必須忽略一些非常明顯的東西。我需要執行一個C程序,實時顯示它的輸出,並最終解析它的最後一行,這應該是直接的,因爲最後一行打印爲總是一樣。無緩衝的子流程輸出(最後一行缺失)

process = subprocess.Popen(args, shell = True, 
          stdout = subprocess.PIPE, stderr = subprocess.PIPE) 

# None indicates that the process hasn't terminated yet. 
while process.poll() is None: 

    # Always save the last non-emtpy line that was output by the child 
    # process, as it will write an empty line when closing its stdout. 
    out = process.stdout.readline() 
    if out: 
     last_non_empty_line = out 

    if verbose: 
     sys.stdout.write(out) 
     sys.stdout.flush() 

# Parse 'out' here... 

但是,偶爾會出現最後一行不打印。 Popens的bufsize的默認值爲0,所以它應該是無緩衝的。我也嘗試過,在退出之前將C++代碼加入fflush(標準輸出),但似乎在退出程序之前絕對不需要刷新流。

想法任何人?

+1

如果子進程生成足夠的輸出來填充其OS管道緩衝區,則子進程掛起。除非您從管道讀取數據,否則不要使用PIPE。你可以使用'deque(iter(process.stdout.readline,b''),maxlen = 1).pop()'來獲得最後一行。或[逐行讀取:'在iter中的行(process.stdout.readline,b''):...'](http://stackoverflow.com/a/17698359/4279) – jfs 2014-09-21 16:12:39

回答

2

readline()必須緩衝文本,等待換行。

您將始終存在爭用條件 - 沒有任何數量的未緩衝流將處理您處理一條線,然後檢查退出,然後讀取一條線的事實,因此,如果子流程退出,重新處理一條線,你不會讀其他任何東西。此外,shell可能會引入自己的緩衝區。

所以,你既可以:

  1. 使用communicate()而放棄詳細輸出的子進程運行時。

  2. 確保在過程退出後繼續閱讀,直到獲得EOF。

我還建議更改您的代碼,以便您不必使用shell=True

3

問題在於,您正在讀取行,直到進程退出,(process.poll()),而您因使用shell標誌而使用緩衝。

您將不得不繼續閱讀process.stdout,直到您到達文件末尾或空行。