2015-04-07 80 views
1

上週我發佈了類似的question,這篇文章反映了我的試驗和我現在面臨的問題。Python - 如何在subprocess.Popen中從PIPE讀取非阻塞?

通過Popen調用的程序是一個命令行程序。我使用一個線程從隊列中讀取一個項目並將其發送到stdin,並從stdout獲取響應。但它proc.stdout.read()中掛起。我確實看到它在上週五的預期輸出中正常工作,然後當我今天做了一些更改時,它會掛起。我所做的更改將使用readlines()取代read()並使用循環來迭代結果。我知道readlines()可能會阻止,但是當我將代碼翻轉到上週五的read()時,它也會阻止。我現在完全迷失了。任何可能的原因?

下面是代碼從隊列中取得一個句子,其提供給Java程序得到迴應:

''' below is the code for worker thread. ''' 
def readQueue(proc, queue): 
    print 'enter queueThread.\n' 
    global notEmpty 
    notEmpty = True 
    while notEmpty: 
     try: 
      sen = queue.get() 
      proc.stdin.write(sen.strip()) 
      res = proc.stdout.read() 
      print res.strip(), ' ', sen 
      queue.task_done() 
     except Empty: 
      break 
    print 'leave queueThread.' 

下面的主線是從文件中讀取每一行,並把它放在一個隊列中的工作線程逐項處理:

def testSubprocess(): 
    ee = open('sentences.txt', 'r') 
    #ff = open('result.txt', 'w') # print it to stdout first before really write to a file. 
    lines = ee.readlines() 
    cmd = ['java', 
      '-cp', 'someUsefulTools.jar', 
      'className', 
      '-stdin',] # take input from stdin 
    proc = Popen(cmd, stdout=PIPE, stdin=PIPE, stderr=PIPE, bufsize=-1, universal_newlines=True) 
    q = Queue() 
    for sen in lines: 
     q.put(sen.strip()) 
    readThread = Thread(target=readQueue, args=(proc, q)) 
    readThread.daemon = True 
    readThread.start() 
    print 'Main thread is waiting...\n' 
    q.join() 
    global notEmpty; notEmpty = False 
    print 'Done!' 
+1

道歉,如果我誤解你的代碼,這是不行的,但是我發現我可以堵塞這種方式停止管道。 (我沒有很多python線程的經驗)在定義「proc」之後,添加這個:「fcntl.fcntl(proc,fcntl.F_SETFL,os.O_NONBLOCK)」如果proc被定義爲類型「pipe 「這應該阻止它阻止。你可能需要導入fcntl。 – Aphire

+0

@Aphire不知道我是否正確,它似乎「fcntl」用於linux/unix環境,對吧? (我的工作環境是windows) –

+0

想象一下,你給java程序發送一個句子:你怎麼知道什麼時候停止讀取響應:它是否總是* 10個字節或者它總是*單行還是你想要讀直到EOF即,每個進程只能回答**單個**問題? – jfs

回答

1

來自子流程的管道是類似文件的對象。

對這些對象的方法read()將所有內容都讀入內存,直到達到EOF爲止,如果沒有指定應該讀取多少內容,請參閱文檔:https://docs.python.org/2/library/stdtypes.html#file.read

如果您不想要這種行爲,您必須設置想要閱讀的尺寸。嘗試將其設置爲1個字節?

這同樣適用於readlines(),請參閱文檔:https://docs.python.org/2/library/stdtypes.html#file.readlines

+0

已嘗試並設置要讀取的大小。問題依然存在。幾乎要放棄並轉向[pexpect](https://pexpect.readthedocs.org/en/latest/)。 –

+0

某些程序在通過pexpect執行時可能會有不同的行爲,因爲程序可以檢測它們是否在終端(TTY設備)中運行。不知道Java程序是否可以做到這一點。例如,如果我在我的系統上運行'ps aux','ps'檢測到終端只有80個字符寬,並相應地縮短了行。如果我們將輸出輸出到文件中(如使用子流程),它將不知道終端的寬度,因此不會縮短行數。 –