2010-12-13 3 views
2

J'ai un script Perl qui doit lancer un autre processus en arrière-plan et quitter sans attendre que l'autre script se termine. Il y a beaucoup de threads sur StackOverflow qui couvrent comment attendre en Perl ou comment ne pas attendre d'autres langages de programmation, mais je n'arrive pas à trouver la bonne réponse pour Perl.Initialisation du processus d'arrière-plan non-en attente en Perl

J'ai beaucoup lu et je pensais que je faisais les bonnes choses, mais aucune de mes tentatives semblent fonctionner correctement. Voici toutes les variations que je l'ai essayé jusqu'à présent en vain:

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 &|); 

Avec chacun de ces processus parent continue d'attendre l'enfant à terminer avant de quitter. S'il vous plaît laissez-moi savoir ce que je fais mal et la bonne façon de bifurquer le processus d'arrière-plan.

Merci d'avance pour votre aide!


Code complet pour faciliter le débogage. Notez que les appels API-> Fonction() sont des modules orientés objet de notre base de code utilise pour des fonctions spécifiques que les interactions de base de données, etc:

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}; 
} 
+0

Le parent attend la fermeture de l'E/S de l'enfant. Utilisez (ou au moins regardez) Proc :: Daemon et 'perldoc -q daemon' pour savoir comment dissocier le parent de l'enfant. – runrig

+0

Vous allez 'accepter' une réponse ici? – runrig

Répondre

4

Le premier est conçu pour fonctionner de cette façon - system exécute la commande et se termine pour qu'il se termine.

Les deux derniers sont également conçus de cette façon - exec est spécifiquement conçu pour ne jamais revenir. Il remplace essentiellement le processus parent par le processus enfant.

Cependant, le second devrait faire l'affaire: la commande lancée à partir de l'appel system est shell, à laquelle est donnée votre chaîne à exécuter. Comme la chaîne se termine par "&", cela signifie que le shell lancera votre commande en arrière-plan et terminera sa propre exécution après ce lancement.

Pouvez-vous s'il vous plaît poster plus de code illustrant comment # 2 n'a pas fonctionné?

Aussi, voir ce qui se passe si vous essayez des accents graves ou QX:

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

En outre, comme un moyen de réduire inconnues, pouvez-vous s'il vous plaît exécutez la commande suivante et dites-moi ce qui imprime:

my $output = qx|(echo "AAAAAAA"; /bin/date; sleep 5; /bin/date; echo "BBBBBBB") &|; 
print $output; 
+0

Simplement par souci d'exhaustivité, voici l'entrée perlfaq quelque peu pertinente: http://perldoc.perl.org/perlfaq8.html#How-do-I-start-a-process-in-the-background? – Hugmeir

+0

Je ne pense pas que votre exemple retournera une sortie utile. – mkb

+0

@DVK - Je pensais que le second était correct aussi, mais le script attend définitivement le processus fils pour finir. Si je commente la ligne system() le script parent sort presque immédiatement et avec cette ligne il faut 3-4 secondes pour sortir, ce qui est la durée d'exécution de l'enfant. J'ai essayé qx et j'ai aussi essayé de faire des backticks mais ni l'un ni l'autre n'ont fini par exécuter l'enfant. Je ne suis pas sûr de ce que je peux fournir d'autre pour aider au dépannage. Des idées? –

0

fourche à l'aide est un bon moyen de processus d'arrière-plan:

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 
+0

Je viens de tester cela et le parent attend toujours dans ce cas. –

+0

C'est étrange. Êtes-vous sûr de mettre l'instruction exit dans le bloc enfant? – Naveed

+0

Je l'ai fait. Le tout est très étrange en effet. C'est pourquoi j'ai posté ici. D'autres idées sur ce qui pourrait se passer? –

3

appelez-vous fork() avant d'appeler system ou 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 
} 
+0

@mobrule - Je n'utilise pas fork(). Lequel des éléments ci-dessus est le bon pour déclencher un processus d'arrière-plan que le parent n'attend pas? Je suppose que c'est celui qui utilise system(). –

+0

Ils sont à peu près équivalents. – mkb

+0

@ mobrul/@ Matt - Les deux font toujours attendre le parent. Des idées comment modifier afin que le parent n'attend pas? –

3

Vous devez dissocier l'enfant du parent. Voir le démon perldoc -q. Ou Proc::Daemon

+0

Je ne veux pas le lancer en tant que démon. Je veux juste lancer un processus distinct si nécessaire. D'autres suggestions? –

+2

@Russell C. - vous n'avez pas besoin de courir en tant que démon "forever" - commencez simplement comme un, faites votre travail et quittez. Il n'y a absolument rien de techniquement exigeant que le démon fonctionne pour toujours. +1 – DVK