Запустить саб в Perl-скрипте в зависимости от времени? - PullRequest
6 голосов
/ 27 августа 2011

У меня есть Perl-скрипт, который постоянно запускается как демон.Я хочу запустить подфункцию в скрипте perl, который основан на времени (или таймере), чтобы каждые 2 часа она выполняла эту подфункцию и продолжала циклЯ думаю получить время эпохи и просто проверить его несколько раз в цикле, и как только оно превысит 2 часа, он запускает подфункцию.Есть ли лучший способ сделать это в Perl?

Спасибо,
LF4

Ответы [ 3 ]

9 голосов
/ 27 августа 2011

Это зависит от того, должно ли быть 2 часа с момента начала последнего запуска подпрограммы или с момента окончания последнего выполнения.


1) Если последнее (2 часа между окончанием выполнения последней подпрограммы и началом новой), решение cespinoza является совершенно приемлемым (бесконечный цикл и вызовите sleep(7200); после выполнения подпрограммы).

my $timeout = 7200;
while (1) {
    dostuff();
    sleep($timeout);
};

Единственная проблема с этим заключается в том, что он не может справиться со случаем, когда dostuff() занимает вечность, например застрять - для обсуждения, почему это важная ситуация для рассмотрения и подходы к решению, см. ниже.


2) Если первое (2 часа между начальными точками), у вас есть три варианта, связанных с обработкой времени выполнения подпрограммы, которое превышает 2 часа [0] . Ваши 3 варианта, подробно объясненные ниже, являются либо:

2a) запустить новую подпрограмму, пока старая продолжает работать (параллельно);

2b) запустить новую подпрограмму ПОСЛЕ окончания старой;

2c) запустить новую подпрограмму, но сначала остановить выполнение предыдущей.

2a и опции 2c требуют, чтобы вы установили alarm() на 2 часа и различались тем, что происходит при срабатывании тревоги.

[0] ПРИМЕЧАНИЕ: поскольку любая подпрограмма может потребовать по крайней мере НЕКОТОРЫХ ресурсов с ПК, всегда есть - хотя и небольшая - вероятность того, что она превысит 2 часа, поэтому вам нужно выбрать один из этих трех вариантов обработки такого сценария.


2a) Начинайте каждые 2 часа, параллельно, если не завершено, старое выполнение.

Эта опция, по сути, реализует функциональность cron.

Каждый раз, когда вы слышите слово параллельно, вы, вероятно, отключите процесс.

my $timeout = 7200;
while (1) { # Not tested!
    eval {
        local $SIG{ALRM} = sub { die "alarm\n" };
        if (!defined($child_pid = fork())) {
            die "cannot fork: $!\n";
        } elsif (!$child_pid) { # Child
            dostuff();
            exit;
        } # Parent continues to sleep for 2 hours
        alarm $timeout; # You need it in case forking off take >2hrs
        sleep; # forever
    };
    die unless $@ eq "alarm\n"; # propagate unexpected errors
    # We don't need to check if $@ is true due to forever sleep
}

2b) Начинайте каждые 2 часа, если старый не закончил, дайте ему поработать до конца

Это можно перефразировать как «стартовое задание, если оно завершается быстрее, чем через 2 часа, оставайтесь на ночь»

my $timeout = 7200;
while (1) {
    my $start = time;
    dostuff();
    my $end = time;
    my $lasted = $end - $start;
    if ($lasted < $timeout) {  
        sleep($timeout - $lasted);
    }
};

2c) Начинайте каждые два часа, если предыдущий не закончился, тайм-аут и убейте его

Всякий раз, когда вы видите такую ​​логику, тревога, очевидно, является ответом.

while (1) {
    my $finished = 0;
    eval {
        local $SIG{ALRM} = sub { die "alarm\n" };
        alarm 7200;
        dostuff();
        $finished = 1;
        sleep; # forever
    };
    die unless $@ eq "alarm\n"; # propagate unexpected errors
    warn "Timed out!!!\n" unless $finished
}

P.S. Как отметил cespinoza, вам нужно каким-то образом демонизировать скрипт (убедитесь, что он не будет убит при выходе из оболочки, запустившей его), с помощью средств Unix (например, запуск его как nohup) или Perlish (поиск daemonize + Perl на Stackoverflow для механики этого).

2 голосов
/ 27 августа 2011

Что-то вроде crontab будет лучше, если вы будете выполнять такую ​​работу по расписанию.Однако, если вы хотите запустить демон Perl, вам придется использовать какой-то обработчик событий.Два варианта с моей головы: POE и AnyEvent.

1 голос
/ 27 августа 2011

Возможно, вы захотите проверить Расписание :: Cron для планирования и выполнения задач.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...