Я часто использую следующий шаблон для установки верхней границы на время выполнения конкретного фрагмента кода в Perl:
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 ($@) {
# handle timeout condition.
}
Мои вопросы:
Вы, вероятно, захотите посмотреть Sys :: SigAction . Я сам им не пользовался, но у него есть несколько восторженных отзывов .
Одна вещь, на которую следует обратить внимание, - это если "вещи, которые могут отключиться по таймауту", используют сами сна
или будильник
. Кроме того, в коде обработки ошибок я предполагаю, что вы готовы к ошибкам, отличным от тайм-аута.
Будьте осторожны с обработкой сигналов. Perl получает сигналы асинхронно, и они могут быть потеряны или мешать друг другу, если сигнал получен в то время, когда другой сигнал обрабатывается обратным вызовом.
Поддержка Win32 библиотеками обработки событий довольно слабая в Perl (мне приходится поддерживать не-цигвин Win32), поэтому я обычно использую простой цикл опроса для тайм-аутов:
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);
Таймер сна можно легко сделать настраиваемым пользователем или вызывающей стороной, и если вы не делаете очень узкий цикл или у вас есть несколько вызывающих сторон, ожидающих цикл (где вы можете получить гонку или мертвую блокировку), это простой, надежный и кросс-платформенный способ реализации тайм-аута.
Также обратите внимание, что накладные расходы цикла означают, что вы не можете гарантировать абсолютное соблюдение тайм-аута. $test_condition, декремент, сборка мусора и т.д. могут помешать.