2013-06-24 23 views
3

Perl 5.14從股票Ubuntu Precise回購。嘗試寫一個簡單的包裝並監控對複製從一個流至另一個的進展:Perl - 無法刷新STDOUT或STDERR

use IO::Handle; 
while ($bufsize = read (SOURCE, $buffer, 1048576)) { 
    STDERR->printflush ("Transferred $xferred of $sendsize bytes\n"); 
    $xferred += $bufsize; 
    print TARGET $buffer; 
} 

如預期(寫入每個1M緩衝器被讀出時間的線)這不執行。我最終看到第一行(空白值爲$ xferred),然後什麼都沒有,直到第7行和第8行(在8MB傳輸)上刷新。幾個小時一直在我的腦海裏 - 我讀過perldocs,我讀過經典的「飽受緩衝」的文章,我試過從select和$ | ++到IO :: Handle到binmode( STDERR,「:: unix」)給你命名。我也嘗試使用IO :: Handle(TARGET-> flush)對每行進行TARGET沖洗。沒有骰子。

有沒有人遇到過這個?我沒有任何想法。睡一秒鐘「修復」了問題,但顯然我不想在每次讀取緩衝區時都要睡一會兒,這樣我的進度就會在屏幕上輸出!

FWIW,無論我輸出到STDERR還是STDOUT,問題都是一樣的。

+2

最初分配給STDERR的句柄開始自動刷新,所以如果你不弄亂它,只需要一個普通的'print'即可。 – ikegami

+0

@ikegami - 對不起,我打字的時候錯過了。我確實看到所有傳輸8MB的8行(如圖所示以1MB塊緩存),但在傳輸結束時它們全部出現。問題編輯得當。 –

+0

@ikegami - 一個正常的打印沒有做;我開始使用普通打印,並給了我緩衝的行爲,然後我嘗試設置$ |,然後我嘗試使用IO :: Handle的自動刷新和刷新方法,然後嘗試使用syswrite而不是打印,然後嘗試如上所示的printflush 。沒有什麼會改變行爲,包括使用STDOUT而不是STDERR - 我得到輸出的第一行,然後在傳輸過程中長時間停頓,然後在傳輸結束時全部8行同時刷新。 –

回答

5

Perl read調用fread(3)而不是read(2)

這意味着它通過libc可能是使用比你更大的內部緩衝區;即它將獲得所有要接收的數據,然後以1MB爲增量快速向您發送數據。

如果這個猜想是正確的,可能是的解決方案中使用sysread,這就要求read(2),而不是read

+0

你絕對正確。問題不是STDERR沒有沖洗,問題是我的INPUT沒有沖洗到常規處理它,儘管在讀取調用中規定了緩衝區大小! –