كيف يمكنني جعل بيرل انتظر العمليات الفرعية التي بدأت في الخلفية مع النظام ()؟

StackOverflow https://stackoverflow.com/questions/911520

سؤال

لدي بعض رمز PERL الذي ينفذ برنامج نصي شل لمعلمات متعددة، لتبسيط، سأفترض أن لدي رمز يشبه هذا:

for $p (@a){
    system("/path/to/file.sh $p&");
}

أود أن أفعل بعض الأشياء الأخرى بعد ذلك، لكنني لا أستطيع إيجاد طريقة لانتظار جميع عمليات الأطفال لإنهاءها قبل الاستمرار.

سيكون تحويل الكود لاستخدام شوكة () صعبا. أليس هناك طريقة أسهل؟

هل كانت مفيدة؟

المحلول

باستخدام شوكة / exec / الانتظار ليس سيئا للغاية:

my @a = (1, 2, 3);
for my $p (@a) {
   my $pid = fork();
   if ($pid == -1) {
       die;
   } elsif ($pid == 0) {
      exec '/bin/sleep', $p or die;
   }
}
while (wait() != -1) {}
print "Done\n";

نصائح أخرى

سوف تضطر إلى تغيير شيء ما، مما يتغير رمز الاستخدام لاستخدام الشوكة ربما يكون أكثر بساطة، ولكن إذا كنت ميتا على مجموعة ضد استخدام الشوكة، فيمكنك استخدام برنامج نصي شل التفاف الذي يلمس ملف عند الانتهاء ثم رمز Perl الخاص بك تحقق من وجود الملفات.

هنا هو التفاف:

#!/bin/bash

$*

touch /tmp/$2.$PPID

سيكون رمز Perl الخاص بك:

for my $p (@a){
    system("/path/to/wrapper.sh /path/to/file.sh $p &");
}
while (@a) {
    delete $a[0] if -f "/tmp/$a[0].$$";
}

لكنني أعتقد أن رمز التشجيع أكثر أمانا ويوضح:

my @pids;
for my $p (@a) {
    die "could not fork" unless defined(my $pid = fork);\
    unless ($pid) { #child execs
        exec "/path/to/file.sh", $p;
        die "exec of file.sh failed";
    }
    push @pids, $pid; #parent stores children's pids
}

#wait for all children to finish
for my $pid (@pids) {
    waitpid $pid, 0;
}

قد يكون التحويل إلى شوكة () صعبا، لكن هذه هي الأداة الصحيحة. النظام () مكالمة حظر؛ يمكنك الحصول على سلوك عدم الحظر عن طريق تنفيذ قذيفة وإخباره بتشغيل البرامج النصية الخاصة بك في الخلفية. هذا يعني أن بيرل ليس لديه فكرة عما قد يكونه شامل الأطفال، مما يعني أن البرنامج النصي لا يعرف ماذا ينتظر.

يمكنك محاولة توصيل PIDS حتى البرنامج النصي PERL، ولكن هذا يخرج بسرعة. استخدام شوكة ().

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top