2010-03-11 16 views
15

Ich benutze das folgende Muster häufig eine obere Schranke auf die Laufzeit eines bestimmten Codefragment in Perl zu setzen:Möglichkeiten, Timeouts in Perl zu machen?

my $TIMEOUT_IN_SECONDS = 5; 
eval { 
    local $SIG{ALRM} = sub { die "alarm\n" }; 
    alarm($TIMEOUT_IN_SECONDS); 
    # do stuff that might timeout. 
    alarm(0); 
}; 
if ([email protected]) { 
    # handle timeout condition. 
} 

Meine Fragen:

  • Ist dies der richtige Weg, es zu tun?
  • Gibt es Umstände, unter denen die Laufzeit $ TIMEOUT_IN_SECONDS überschreiten kann, oder ist die obige Methode kugelsicher?
+1

Ihr eval ist anfällig für einen bösen Fehler. Lesen Sie die Try :: Tiny-Dokumentation für eine detaillierte Erklärung: http://search.cpan.org/perldoc?Try::Tiny – daotoad

Antwort

9

Sie möchten wahrscheinlich Sys::SigAction betrachten. Ich habe es selbst nicht benutzt, aber es hat some glowing reviews.

Eine Sache, auf die man achten sollte, ist, ob "Sachen, die möglicherweise Timeout" sleep oder alarm selbst verwenden. Außerdem nehme ich an, dass Sie im Fehlerbehandlungscode auf andere Fehler als eine Zeitüberschreitung vorbereitet sind.

+0

Könnten Sie bitte den Fall erklären, wenn die Anwendung den Ruhezustand selbst verwendet? Und wie löst man es? –

2

Vorsicht bei der Signalverarbeitung. Perl empfängt Signale asynchron und sie können verloren gehen oder sich gegenseitig stören, wenn ein Signal empfangen wird, während ein anderes Signal durch den Rückruf behandelt wird.

Event-Handling-Bibliotheken Win32-Unterstützung ist ziemlich so lala in Perl (I nicht-Cygwin Win32 unterstützen müssen), so dass ich verwenden in der Regel eine einfache Abfrageschleife für Timeouts:

use Time::HiRes qw(sleep); 

sub timeout { 
    my $timeout = shift; 
    my $poll_interval = shift; 
    my $test_condition = shift; 
    until ($test_condition->() || $timeout <= 0) { 
    $timeout -= $poll_interval; 
    sleep $poll_interval; 
    } 
    return $timeout > 0; # condition was met before timeout 
} 

my $success = timeout(30, 0.1, \&some_condition_is_met); 

Der Sleep-Timer kann leicht vom Benutzer oder vom Anrufer konfigurierbar gemacht werden, und es sei denn, Sie machen eine extrem enge Schleife oder haben mehrere Anrufer, die auf die Schleife warten (wo Sie mit einem Rennen oder einer toten Sperre enden können), ist es einfach, zuverlässig und kreuzend -Plattformform, um ein Timeout zu implementieren.

Beachten Sie auch, dass der Schleifenoverhead bedeutet, dass Sie nicht garantieren können, dass das Timeout absolut eingehalten wird. $ test_condition, das Dekrement, die Garbage-Collection usw. können stören.

+1

Dies beantwortet die Frage nicht. Dieser Code wird nicht das gleiche Ziel wie der OP-Code erreichen. Wenn some_condition_is_met() nie zurückkehrt, wird das Programm hängen. –

4

Sie könnten auch versuchen Time::Out. Ich mag die Syntax und verschachtelte Timeouts werden unterstützt.

+1

+1 Dieses Modul behandelt alle Sorgen über verschachtelte Timeouts für Sie, sodass Sie sich nicht um alle Randfälle kümmern müssen. Es ist zu alarmieren, was try :: tiny zu eval ist. – mikew

+0

Ist das Time :: Out Modul threadsafe? In meinem Fall brauche ich ein Timeout pro Thread in meiner Anwendung. – reedog117

+0

@ reedog117: Ich habe keine Ahnung ... –

Verwandte Themen