Запуск фонового процесса без ожидания в Perl

У меня есть сценарий Perl, который должен запустить другой процесс в фоновом режиме и выйти, не дожидаясь завершения другого сценария. На StackOverflow есть множество тем, посвященных тому, как ждать в Perl или как не ждать в других языках программирования, но я не могу найти правильного ответа для Perl.

Я прочитал довольно много и подумал, что делаю правильные вещи, но ни одна из моих попыток, похоже, не работает правильно. Вот все варианты, которые я пробовал до сих пор безрезультатно:

system(qq|perl /util/script.pl $id|);

system(qq|perl /util/script.pl $id &|);

exec(qq|perl /util/script.pl $id|);

exec(qq|perl /util/script.pl $id &|);

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

Заранее спасибо за помощь!


Полный код для помощи в отладке. Обратите внимание, что вызовы API->Function() являются объектно-ориентированными модулями, которые наша кодовая база использует для определенных функций, взаимодействий с базой данных и т. д.:

sub Add {
    my $self = shift;
    my $domain = shift;

    if(!$self->IsValid($domain)) { return; }

    my $SQL = qq| insert into domains set added=NOW(),domain=| . API->Database->Quote($domain);
    my $sth = API->DatabaseQuery($SQL);

    $SQL = qq| select last_insert_id() |;
    $sth = API->DatabaseQuery($SQL);
    my $id = $sth->fetchrow_array();

    my $command = qq|perl /home/siteuser/util/new.pl $id &|;
    system($command);

    return {'id'=>$id,'domain'=>$domain};
}

person Russell C.    schedule 13.12.2010    source источник
comment
Родитель ожидает закрытия IO в дочернем элементе. Используйте (или хотя бы посмотрите) Proc::Daemon и «perldoc -q daemon», чтобы узнать, как отделить родителя от дочернего.   -  person runrig    schedule 17.12.2010
comment
Вы собираетесь «принять» любой ответ здесь?   -  person runrig    schedule 16.11.2012


Ответы (4)


Первый предназначен для работы таким образом - system выполняет команду и доводит ее до конца.

Последние два также разработаны таким образом - exec специально разработан, чтобы никогда не возвращаться. Он в основном заменяет родительский процесс дочерним процессом.

Однако второй должен сделать свое дело: команда, запущенная из вызова system, является оболочкой, которой дается ваша строка для выполнения. Поскольку строка заканчивается на «&», это означает, что оболочка запустит вашу команду как фоновый процесс и завершит собственное выполнение после этого запуска.

Не могли бы вы опубликовать больше кода, иллюстрирующего, как # 2 не работает?

Также посмотрите, что произойдет, если вы попробуете обратные кавычки или qx:

my $output = qx|perl /util/script.pl $id &|;
print $output;

Кроме того, как способ сокращения неизвестных, не могли бы вы запустить следующее и сказать мне, что печатает:

my $output = qx|(echo "AAAAAAA"; /bin/date; sleep 5; /bin/date; echo "BBBBBBB") &|;
print $output;
person DVK    schedule 13.12.2010
comment
Просто для полноты картины вот несколько релевантная запись perlfaq: perldoc.perl.org/? - person Hugmeir; 13.12.2010
comment
Я не думаю, что ваш пример вернет какой-либо полезный результат. - person Matt K; 13.12.2010
comment
@DVK - я думал, что и второй вариант тоже правильный, но скрипт определенно ожидает завершения дочернего процесса. Если я закомментирую строку system(), родительский скрипт выйдет почти сразу, и с этой строкой для выхода потребуется 3-4 секунды, а именно столько времени требуется для выполнения дочернего элемента. Я попробовал qx, а также обратные кавычки, но ни один из них не запустил ребенка вообще. Я не уверен, что еще я могу предоставить, чтобы помочь с устранением неполадок. Любые идеи? - person Russell C.; 13.12.2010
comment
@ Мэтт - ты прав. qx|| пример ничего не возвращает. - person Russell C.; 13.12.2010
comment
@Matt Kane - он предназначен для возврата обычного фонового вывода оболочки (например, PID фоновых процессов). Возможно, потребуется перенаправление STDERR - сейчас передо мной нет xtterm, поэтому я не помню, идет ли вывод & на стандартный вывод. - person DVK; 13.12.2010
comment
@Russell, не могли бы вы опубликовать свой точный код? Там может быть какая-то странная морщинка, например, имя сценария или что-то в этом роде. - person DVK; 13.12.2010
comment
@Russell - я добавил пример кода, который я хотел бы, чтобы вы попробовали запустить, не могли бы вы сообщить о результатах? Кроме того, проверьте, какое значение имеет $id. - person DVK; 13.12.2010
comment
@DVK - вот вывод qx|| звонок, который вы просили: AAAAAAA Пн, 13 декабря 10:57:12 PST 2010 Пн, 13 декабря 10:57:17 PST 2010 BBBBBBB - person Russell C.; 13.12.2010
comment
@Рассел, пожалуйста, сделай print Data::Dumper->Dump([$id]) тоже. - person DVK; 14.12.2010
comment
@DVK - поле $id представляет собой просто строку вида 100000. Вывод дампера: $VAR1 = '100000'; - person Russell C.; 14.12.2010

Вы звоните fork() перед звонком system или exec?

my $pid = fork();
if (defined($pid) && $pid==0) {
    # background process
    my $exit_code = system( $command );
    exit $exit_code >> 8;
}


my $pid = fork();
if (defined($pid) && $pid==0) {
    # background process
    exec( $command );
    # doesn't^H^H^H^H^H^H shouldn't return
}
person mob    schedule 13.12.2010
comment
@mobrule - я не использую fork(). Что из вышеперечисленного является правильным для запуска фонового процесса, которого родитель не ждет? Я предполагаю, что это тот, который использует system(). - person Russell C.; 13.12.2010
comment
Они оба примерно эквивалентны. - person Matt K; 13.12.2010
comment
@mobrul/@Matt - Оба все еще заставляют родителя ждать. Любые идеи, как изменить, чтобы родитель не ждал? - person Russell C.; 13.12.2010
comment
Правильный способ — использовать fork() для создания фонового процесса, а затем запускать system или exec из этого фонового процесса. - person mob; 13.12.2010
comment
(Поскольку это Perl, я должен был начать последний комментарий с буквы А...) - person mob; 13.12.2010
comment
@mobrule - Так почему это все еще блокирует родителя, когда мы делаем системный вызов? - person Russell C.; 13.12.2010

Вам нужно отделить ребенка от родителя. См. демон perldoc -q. Или Proc::Daemon

person runrig    schedule 13.12.2010
comment
Я не хочу запускать его как демон. Я просто хочу, чтобы начать это отдельный процесс по мере необходимости. Есть другие предложения? - person Russell C.; 16.12.2010
comment
@Russell C. - вам не нужно работать как постоянный демон - просто начните как один, выполните свою работу и выйдите. Нет абсолютно ничего, что технически требовало бы, чтобы демон работал вечно. +1 - person DVK; 17.12.2010

Использование fork — хороший способ фоновых процессов:

my $pid = fork;
die "fork failed" unless defined $pid;
if ($pid == 0) {
    # child process goes here
    do '/util/script.pl';
    exit;
}
# parent process continues here
person Naveed    schedule 13.12.2010
comment
Я только что проверил это, и в этом случае родитель все еще ждет. - person Russell C.; 13.12.2010
comment
Это странно. Вы уверены, что поместили оператор выхода внутри дочернего блока? - person Naveed; 15.12.2010
comment
Я сделал. Все это действительно очень странно. Вот почему я разместил здесь. Любые другие идеи, что может происходить? - person Russell C.; 15.12.2010
comment
Я бы посоветовал вам заменить /util/script.pl простой программой, такой как: for (1 .. 10) { print sleep $_ ...\n; sleep 1 } Это может помочь вам отладить проблему. - person Naveed; 16.12.2010