2011-05-24 8 views
5

En el siguiente código, intento realizar una operación simple de archivo de cola. Supongamos que foo.txt está completamente vacío. Esperaría que el primer can_read() bloqueara pero no lo hace. Tampoco las llamadas can_read en sysreadline() bloquean ni esperan. En cambio, lo que ocurre es que el primer can_read devuelve inmediatamente el identificador a foo.txt y el primer can_read en sysreadline hace lo mismo. El sysread no devuelve nada porque no hay nada que leer, lo que resulta en una espera ocupada dentro de sysreadline. ¿Cómo puede ser esto? Sé que una lata selecta puede terminar temprano debido a una señal o un identificador de archivo cerrado, pero no veo ninguna oportunidad para eso aquí. De hecho, cuando aparece texto (con una nueva línea) en foo.txt, se imprime. No veo por qué el código no se bloquea indefinidamente, ya que el primero puede leer cuando no hay nada que leer. Además de desperdiciar la CPU, hace que sea imposible cola múltiples archivos al mismo tiempo porque siempre se quedará atascado en la primera espera ocupada. Siento que tengo que estar pasando por alto algo sencillo aquí ...perl can_read devuelve el controlador cuando no hay nada que leer

Este es el 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

Quizás 'File :: Tail' puede ser útil. – TLP

+0

Tiene '>' en vez de '<' en su abierto. Pero incluso además de eso, no estoy seguro de que la E/S no bloqueante tenga sentido para esto. Una tubería/FIFO o toma de corriente puede estar en un estado en el que está conectado pero esperando más datos. Cuando lee un archivo normal, o está al final o no lo está. No conozco una manera para que el lector rastree si todavía hay alguien más escribiendo en el archivo. Tal vez encuesta 'fstat()'? – Andy

+0

@andy, que es un error tipográfico en la pasta de stackoverflow. Tuve que reemplazar el original frankc

Respuesta

7

El regreso de select significa "leer no bloqueará (es decir, esperar por siempre por algún evento externo que suceda) ", y no" datos disponibles ". Leyendo archivos del disco nunca bloquea, devuelve 0 inmediatamente en EOF.

Así que probablemente estés mejor con File::Tail que sugiere @TLP.

Cuestiones relacionadas