2013-05-27 74 views
43

我有一個名爲1st.py腳本創建一個REPL(讀-EVAL-打印循環):瞭解Popen.communicate

print "Something to print" 
while True: 
    r = raw_input() 
    if r == 'n': 
     print "exiting" 
     break 
    else: 
     print "continuing" 

然後我用下面的代碼推出1st.py

p = subprocess.Popen(["python","1st.py"], stdin=PIPE, stdout=PIPE) 

然後試過這個:

print p.communicate()[0] 

它失敗了,提供了這個回溯:

Traceback (most recent call last): 
    File "1st.py", line 3, in <module> 
    r = raw_input() 
EOFError: EOF when reading a line 

你能解釋一下這裏發生了什麼嗎?當我使用p.stdout.read()時,它永遠掛起。

回答

35

.communicate()寫入輸入(在這種情況下沒有輸入,所以它只是關閉子進程stdin以向子進程指示沒有更多輸入),讀取所有輸出並等待子進程退出。

異常EOFError在子進程中由raw_input()(它預期的數據但得到EOF(無數據))引發。

p.stdout.read()掛起永遠,因爲它試圖在同一時間閱讀從孩子輸出所有的孩子等待輸入(raw_input())導致死鎖。

爲避免你需要閱讀/異步寫入(例如,通過使用線程或選擇),或者確切地知道僵局何時以及有多少讀/寫,for example

from subprocess import PIPE, Popen 

p = Popen(["python", "-u", "1st.py"], stdin=PIPE, stdout=PIPE, bufsize=1) 
print p.stdout.readline(), # read the first line 
for i in range(10): # repeat several times to show that it works 
    print >>p.stdin, i # write input 
    p.stdin.flush() # not necessary in this case 
    print p.stdout.readline(), # read output 

print p.communicate("n\n")[0], # signal the child to exit, 
           # read the rest of the output, 
           # wait for the child to exit 

注:這是一個非常脆弱的代碼,如果讀/寫不同步;它陷入僵局。

當心block-buffering issue(這裏使用"-u" flag that turns off buffering for stdin, stdout in the child來解決)。

bufsize=1 makes the pipes line-buffered on the parent side

+0

可以告訴我 print >> p.stdin,i和p.stdin.write(i) –

+0

這裏'print'是'p.stdin.write(str(i)+「\ n」 ); p.stdin.flush()'。 – jfs

+0

謝謝... 還有一件事請告訴我這個bufsize = 1在做什麼?還有Popen中的「-u」([「python」,「-u」,「1st.py」],stdin = PIPE,stdout = PIPE,bufsize = 1) –

0

您的第二位代碼將第一位代碼作爲帶管道輸入和輸出的子進程啓動。然後它關閉輸入並嘗試讀取其輸出。

第一個代碼嘗試從標準輸入中讀取,但啓動它的過程關閉了其標準輸入,因此它立即到達文件結束,Python變成異常。

+0

謝謝...但我只是不想關閉任何輸入。 我想打印1st.py打印到標準輸出的任何地方。 稍後,我將執行p.stdin.write(「Somthing to input」),然後執行p.communicate()[0]在第二個代碼中打印此代碼。 你能幫我嗎? 我只是不想關閉輸入或輸出。 我是新手,所以不要猶豫,糾正我。 謝謝 –

16

請勿使用溝通(輸入=「」)。它將輸入寫入進程,關閉stdin,然後讀取所有輸出。

做這樣的:

p=subprocess.Popen(["python","1st.py"],stdin=PIPE,stdout=PIPE) 

# get output from process "Something to print" 
one_line_output = p.stdout.readline() 

# write 'a line\n' to the process 
p.stdin.write('a line\n') 

# get output from process "not time to break" 
one_line_output = p.stdout.readline() 

# write "n\n" to that process for if r=='n': 
p.stdin.write('n\n') 

# read the last output from the process "Exiting" 
one_line_output = p.stdout.readline() 

,你會做些什麼來消除誤差:

all_the_process_will_tell_you = p.communicate('all you will ever say to this process\nn\n')[0] 

但由於溝通關閉stdoutstdinstderr,您無法讀取或寫入後你打電話溝通。

+0

感謝您的回覆..但您可以看到我的第一個程序正在等待用戶輸入,並且在此之前它正在打印「要打印的東西」。 所以我想要的是:從第二個過程中,我只想讀取該行(「要打印的東西」)。 和更高版本從這個(第二個進程)我想寫入其標準輸入,然後再次想要讀取任何第一個進程(子進程)正在寫入標準輸出。 那麼,告訴我我該怎麼做? –

+0

我評論了這段代碼。現在應該做你想做的事。它更清楚嗎? – User

+0

當父進程正在等待用戶輸入時,如果使用p.stdout.read()/ readline(),我的父進程會掛起(永久停止)。 –