Подтвердить что ты не робот

Способы выполнения тайм-аутов в Perl?

Я часто использую следующий шаблон, чтобы установить верхнюю границу времени выполнения конкретного фрагмента кода в 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 ([email protected]) {
    # handle timeout condition.
}

Мои вопросы:

  • Правильно ли это сделать?
  • Существуют ли какие-либо обстоятельства, при которых время выполнения может превышать $TIMEOUT_IN_SECONDS, или это вышеописанный метод пуленепробиваемый?
4b9b3361

Ответ 1

Вероятно, вы захотите посмотреть Sys::SigAction. Я не использовал его сам, но он некоторые светящиеся обзоры.

Одна вещь, на которую нужно обратить внимание, - это то, что "материал, который может быть тайм-аут", использует sleep или alarm. Кроме того, в коде обработки ошибок я предполагаю, что вы готовы к ошибкам, отличным от тайм-аута.

Ответ 2

Вы также можете попробовать Time:: Out. Мне нравится синтаксис и вложенные тайм-ауты.

Ответ 3

Соблюдайте осторожность при обработке сигналов. Perl принимает сигналы асинхронно, и они могут быть потеряны или мешать друг другу, если сигнал принят, когда другой сигнал обрабатывается обратным вызовом.

Поддержка Win32 для библиотек обработки событий довольно похожа на Perl (мне нужно поддерживать не-cygwin 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, декремент, сбор мусора и т.д. могут вмешиваться.