for line in sys.stdin


絢麗也塵埃 » for line in sys.stdin

for line in sys.stdin

糾結一個下午和一個晚上了,我想在syslog-ng里面添加一個program destination,程序是用Python寫的,結果發現file destination總是在第一時間就能收到消息,而program則沒有什么動靜,反復測試了好多遍都是如此。man Python,發現了Python有個’-u’參數,man是這樣說的。

-u Force stdin, stdout and stderr to be totally unbuffered. On systems where it matters, also put stdin, std-out and stderr in binary mode. Note that there is internal buffering in xreadlines(), readlines() and file-object iterators (“for line in sys.stdin”) which is not influenced by this option. To work around this, you will want to use “sys.stdin.readline()” inside a “while 1:” loop.

加上’-u’之后,標准輸出打印的內容很快能進入日志文件中,標准輸入還是沒有動靜。當時沒有仔細看這段說明,里面已經指出了for line in sys.stdin並不受影響,而我的代碼偏偏是這樣從標准輸入里面讀數據的。后來無意中在stackoverflow發現有一個人說這樣迭代方式需要等到EOF出現才會開始執行,如果使用sys.stdin.readline()就不會有問題,測試了下發現果然是好用的。

下面兩個例子可以說明問題。在終端中分別運行兩個程序,第一種遍歷方式會等到敲入CRTL+D才會打印輸入的內容。第二種方式輸入一行,回車之后就會打印這行。

?
01
02
03
04
05
06
07
08
09
10
11
12
#!/bin/env
 
import sys
 
for line in sys.stdin:
     print line,
 
line = sys.stdin.readline()
while line:
     print line,
 
     line = sys.stdin.readline()

奇怪的是,我寫Hadoop Streaming Job時,一直都用for line in sys.stdin這種方式遍歷,也沒有出過問題。Hadoop Streaming官方文檔里面的例子用的是readline這種方法。我猜這個應該是Hadoop的數據都保存在本地了,等於用cat的方式給腳本送數據,所以沒有問題。

在網上查資料的時候還發現有人反饋Python使用for line in sys.stdin的一個bug:Issue1633941,就是需要輸入兩次CRTL+D程序才會退出。Ralph Corderoy指出這個和Python 2.6用fread導致的問題,大概的意思是fread讀到的數據長度為0時,它才認為獲取到了EOF。如果沒有得到指定長度的數據,即使數據后面存在EOF,它也會忽略。解決辦法是在循環內使用feof對stdin進行一次判斷,如果結束了就立即退出。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM