簡體   English   中英

subprocess.Popen.stdout - 實時讀取標准輸出(再次)

[英]subprocess.Popen.stdout - reading stdout in real-time (again)

同樣,同樣的問題。
原因是 - 閱讀以下內容后仍然無法使其正常工作:

我的情況是我有一個用C編寫的控制台應用程序,讓我們在循環中采用這個代碼:

tmp = 0.0;   
printf("\ninput>>"); 
scanf_s("%f",&tmp); 
printf ("\ninput was: %f",tmp); 

它不斷讀取一些輸入並寫入一些輸出。

我與它交互的python代碼如下:

p=subprocess.Popen([path],stdout=subprocess.PIPE,stdin=subprocess.PIPE)
p.stdin.write('12345\n')
for line in p.stdout: 
    print(">>> " + str(line.rstrip())) 
    p.stdout.flush() 

到目前為止,每當我讀取表單p.stdout它總是等待,直到進程終止然后輸出一個空字符串。 我嘗試了很多東西 - 但結果仍然相同。

我嘗試過Python 2.6和3.1,但版本並不重要 - 我只需要讓它在某個地方工作。

嘗試寫入和讀取管道到子進程是棘手的,因為兩個方向上的默認緩沖都在進行。 在一個或另一個進程(父進程或子進程)從空緩沖區讀取,寫入完整緩沖區或在系統庫刷新之前等待數據的緩沖區上執行阻塞讀取時,很容易出現死鎖。

對於更適量的數據, Popen.communicate()方法可能就足夠了。 但是,對於超過其緩沖的數據,您可能會遇到停滯的進程(類似於您已經看到的情況?)

您可能希望查找有關使用fcntl模塊以及使一個或另一個(或兩個)文件描述符無阻塞的詳細信息。 在這種情況下,當然,您必須在適當的異常處理中包裝對這些文件描述符的所有讀取和/或寫入,以處理“EWOULDBLOCK”事件。 (我不記得為這些引發的確切Python異常)。

一個完全不同的方法是讓你的父進程使用select模塊和os.fork() ...並且子進程在直接處理任何文件dup()之后執行execve()目標程序。 (基本上你將重新實現Popen()部分,但具有不同的父文件描述符(PIPE)處理。

順便說一下,.communicate,至少在Python的2.5和2.6標准庫中,只能處理大約64K的遠程數據(在Linux和FreeBSD上)。 這個數字可能因各種因素而有所不同(可能包括用於編譯Python解釋器的構建選項,或者鏈接到它的libc版本)。 它不僅僅受到可用內存的限制(盡管JF Sebastian斷言相反),但僅限於更小的值。

bufsize=256參數阻止12345\\n在小於256字節的塊中發送到子進程,就像在省略bufsize或在p.stdin.flush()之后插入p.stdin.flush() p.stdin.write() 默認行為是行緩沖。

在任何一種情況下,您應該至少在阻塞之前看到一個空行,如示例中第一個printf(\\n...)所發出的那樣。

將管道中的讀數推送到一個單獨的線程中,該線程在有一大塊輸出可用時發出信號:

如何從subprocess.Popen.stdout(非阻塞)中讀取所有可用數據?

您的特定示例不需要“實時”交互。 以下作品:

from subprocess import Popen, PIPE

p = Popen(["./a.out"], stdin=PIPE, stdout=PIPE)
output = p.communicate(b"12345")[0] # send input/read all output
print output,

其中a.out是你的示例C程序。

通常,對於與子pexpect的基於對話框的交互,您可以使用pexpect模塊(或Windows上的類似物):

import pexpect

child = pexpect.spawn("./a.out")
child.expect("input>>")
child.sendline("12345.67890") # send a number
child.expect(r"\d+\.\d+") # expect the number at the end
print float(child.after) # assert that we can parse it
child.close()

我有同樣的問題,“proc.communicate()”沒有解決它,因為它等待進程終止。

所以這是適用於我的,在使用Python 3.5.1的 Windows上:

import subprocess as sp
myProcess = sp.Popen( cmd, creationflags=sp.CREATE_NEW_PROCESS_GROUP,stdout=sp.PIPE,stderr=sp.STDOUT)
while i<40:
        i+=1
        time.sleep(.5)
        out = myProcess.stdout.readline().decode("utf-8").rstrip()

我想creationflags和其他參數不是強制性的(但我​​沒時間測試),所以這將是最小的語法:

myProcess = sp.Popen( cmd, stdout=sp.PIPE)
for i in range(40)
            time.sleep(.5)
            out = myProcess.stdout.readline()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM