2014-06-05 48 views
0

如果一系列命令在Linux中進行管道傳輸,則它可以高效地處理它,即。如果最後一個子進程已經終止,它會終止前一個子進程。例如,如何在python子進程的巨大輸入上處理管道「head」?

cat filename | head -n 1 
zcat filename | head -n 1 
hadoop fs -cat /some/path | head -n 1 

在上述每一項中,cat命令都需要相當長的時間,但組合命令執行速度很快。它是如何在內部完成的?第一個命令(cat命令)在head終止後立即由OS給出SIGTERM,SIGKILL?

我想在Python中做類似的事情,並想知道應該做什麼最好的方法。我正在嘗試執行以下操作:

p1 = Popen(['hadoop','fs','-cat',path], stdout=PIPE) 
p2 = Popen(['head','-n',str(num_lines)], stdin=p1.stdout,stdout=PIPE) 
p2.communicate() 
p1.kill() or p1.terminate() 

這是否有效?

+0

爲什麼使用'head'?你可以直接在python中讀取來自p1.stdout的行。看到這個問題:http://stackoverflow.com/questions/1767513/read-first-n-lines-of-a-file-in-python – jbaiter

+0

@jbaiter:同意但仍然沒有回答這個問題。我可能沒有使用'head'並從p1.stdout中讀取,但是我想知道的是,一旦我讀取了所需的行數,是否安全地使用p1.kill()或p1.terminate() ?有更多優雅的方法來實現同樣的目標嗎? –

回答

1

其實,我相信這個過程在頭部關閉時會發送到SIGPIPE。從Wikipedia

SIGPIPE

當它試圖寫入一個管不連接到另一端的過程中的SIGPIPE信號被髮送到一個進程。

而且,從a question on SIGPIPE幾個答案:

...

你看,當與掛起的寫文件描述符被關閉時,發生了SIGPIPE再適合。儘管寫入操作最終會返回-1,但信號的整個要點是要異步通知您寫入不再可能。這是UNIX中管道整體優雅協同結構的一部分。

...

https://stackoverflow.com/a/8369516/2334407


...

https://www.gnu.org/software/libc/manual/html_mono/libc.html

此鏈接說:

管道或FIFO必須在兩端開口同時。如果您從沒有任何進程寫入的管道或FIFO文件讀取(可能是因爲它們全部關閉了文件或退出),則讀取將返回文件結束。寫入沒有讀取過程的管道或FIFO將被視爲錯誤條件;它會生成一個SIGPIPE信號,如果信號被處理或阻塞,則會失敗並顯示錯誤代碼EPIPE。

...

https://stackoverflow.com/a/18971899/2334407


我認爲這是讓錯誤處理正確,而不需要的一切書面形式向管道大量的代碼。

某些程序忽略write()的返回值;如果沒有SIGPIPE,它們將無用地生成所有輸出。

檢查write()的返回值的程序如果失敗,可能會打印一條錯誤消息;這對於破損的管道是不合適的,因爲它對於整個管道來說並不是真正的錯誤。

https://stackoverflow.com/a/8370870/2334407


現在回答你關於什麼是最好的方式做這將是一個問題,我會說不發送任何信號。相反,請根據需要讀取儘可能多的數據,然後關閉管道。操作系統內核隨後會自動清理並將SIGPIPE發送到必要的進程。