2012-02-12 20 views
3

目前,我打個電話這樣的:的Perl:執行多個系統進程,並等待他們在我的Perl腳本結束

system(" ./long_program1 & ./long_program2 & ./long_program3 & wait "); 

我希望能夠在記錄每個長時間運行的命令執行時仍然異步執行它們。我知道系統調用會導致perl生成一個fork,所以可能會這樣嗎?這可以被多個perl fork()和exec()調用所取代嗎?

請幫我找到更好的解決方案。

+0

你要記錄的結束時間或只是開始時間?當進程啓動時,你想記錄哪些信息,當進程退出時你想記錄什麼信息? – ikegami 2012-02-13 10:18:52

回答

6

是的,當然。您可以爲每個要執行的程序分出一個子進程。

您可以做system()exec()分叉後,這取決於你想要多少處理您的Perl代碼在系統調用完成後做(因爲EXEC()在功能上system(); exit $rc;非常相似)

foreach my $i (1, 2, 3) { 
    my $pid = fork(); 
    if ($pid==0) { # child 
     exec("./long_program$i"); 
     die "Exec $i failed: $!\n"; 
    } elsif (!defined $pid) { 
     warn "Fork $i failed: $!\n"; 
    } 
} 

1 while wait() >= 0; 

請注意,如果您需要做很多叉子,您最好通過Parallel::ForkManager來控制它們,而不是手動分叉。

+0

'exec'在許多方面與'system'&'exit'不同。 (事實上​​,'system'使用'exec'。) – ikegami 2012-02-13 03:02:18

+0

@ikegami - 真的,我過於簡單,因爲它不是主問:我會重新字 – DVK 2012-02-13 10:58:44

3

兩種選擇:


use IPC::Open3 qw(open3); 

sub launch { 
    open(local *CHILD_STDIN, '<', '/dev/null') or die $!; 
    return open3('<&CHILD_STDIN', '>&STDOUT', '>&STDERR', @_); 
} 

my %children; 
for my $cmd (@cmds) { 
    print "Command $cmd started at ".localtime."\n"; 
    my $pid = launch($cmd); 
    $children{$pid} = $cmd; 
} 

while (%children) { 
    my $pid = wait(); 
    die $! if $pid < 1; 
    my $cmd = delete($children{$pid}); 
    print "Command $cmd ended at ".localtime." with \$? = $?."\n"; 
} 

我用open3因爲它比短的甚至是微不足道的fork + exec並且因爲它不misattribute exec錯誤您啓動像命令瑣碎fork + exec


use threads; 

my @threads; 
for my $cmd (@cmds) { 
    push @threads, async { 
     print "Command $cmd started at ".localtime."\n"; 
     system($cmd); 
     print "Command $cmd ended at ".localtime." with \$? = $?."\n"; 
    }; 
} 

$_->join() for @threads; 
+0

過有關什麼是優勢,使用多線程,而不是多進程在這樣的情況下? – Blaskovicz 2012-02-13 04:41:07

+0

@Blaskovicz,它不使用線程而不是進程。它啓動完全相同的過程。至於代碼在第一個代碼片段中代碼的優點,它應該很明顯:簡單。 – ikegami 2012-02-13 10:14:15

+0

線程使用選項是美麗的,乾淨的和工作的一種享受!謝謝! – Balthasar 2015-04-23 05:40:19