2011-05-24 32 views
5

在下面的代碼中,我試圖執行一個簡單的文件尾部操作。假設foo.txt是完全空的。我期望第一個can_read()會阻塞,但它不會。 sysreadline()中的can_read調用也不會等待或等待。相反,第一個can_read會立即將​​句柄返回給foo.txt,並且sysreadline中的第一個can_read也會執行相同的操作。 sysread然後不返回任何內容,因爲沒有任何可讀的內容,導致sysreadline內部忙於等待。怎麼會這樣?我知道select可以提前結束,因爲信號或者關閉了文件句柄,但是在這裏我沒有看到任何機會。事實上,當文本在foo.txt中出現(用換行符)時,它將被打印。我不明白爲什麼代碼在沒有任何可讀的情況下不會無限期地阻塞爲第一個can_read。除了浪費cpu之外,它還使得無法同時拖放多個文件成爲可能,因爲在第一個忙碌的等待中你總會陷入困境。我覺得我必須忽視的東西簡單在這裏...perl can_read在沒有東西可讀時返回句柄

這是perl的5.8.8



#!/usr/bin/perl -w 
use strict; 
use IO::Select; 
use IO::Handle; 
use Symbol qw(qualify_to_ref); 

open my $inf, "<", "foo.txt" or die "hey! Can't open foo.txt!\n"; 
my $sel = IO::Select->new(); 
$sel->add($inf); 

while(my @ready = $sel->can_read()){ 

    foreach my $handle (@ready){ 
    my $line = sysreadline($handle); 
    print $line; 
    } 

} 

## 
## deal with buffering for select. from perl cookbook 7.23 
sub sysreadline { 
    my($handle, $timeout) = @_; 
    $handle = qualify_to_ref($handle, caller()); 
    my $infinitely_patient = (@_ == 1 || $timeout new(); 
    $selector->add($handle); 
    my $line = ""; 
SLEEP: 
    until (at_eol($line)) { 
     unless ($infinitely_patient) { 
      return $line if time() > ($start_time + $timeout); 
     } 
     # sleep only 1 second before checking again 
     next SLEEP unless $selector->can_read(1.0); 
INPUT_READY: 
     while ($selector->can_read(0.0)) { 
      my $was_blocking = $handle->blocking(0); 
CHAR:  while (sysread($handle, my $nextbyte, 1)) { 
       $line .= $nextbyte; 
     ##print "next: [$nextbyte]\n"; 
       last CHAR if $nextbyte eq "\n"; 
      } 
      $handle->blocking($was_blocking); 
      # if incomplete line, keep trying 
      next SLEEP unless at_eol($line); 
      last INPUT_READY; 
     } 
    } 
    return $line; 
} 
sub at_eol($) { $_[0] =~ /\n\z/ } 

+2

也許'File :: Tail'可以使用。 – TLP 2011-05-24 18:09:56

+0

你有'''而不是'<'在你打開。但是除此之外,我不確定非阻塞I/O對此有意義。管道/ FIFO或套接字可以處於連接狀態,但正在等待更多數據。從常規文件中讀取時,您可能處於最後或者不是。我不知道有什麼方法讓讀者跟蹤是否有其他人仍在寫入文件。也許輪詢'fstat()'? – Andy 2011-05-24 18:11:01

+0

@andy,這是在stackoverflow粘貼錯誤。我必須用一個實體替換原來的<或者它將被刪除 – frankc 2011-05-24 18:16:17

回答

7

select返回裝置「讀不會阻塞(即永遠等待一些外部事件發生)「,而不是」數據可用「。從磁盤讀取文件永遠不會阻塞,它會立即在EOF處返回0。

因此,您可能更喜歡使用@TLP建議的File::Tail

相關問題