【问题标题】:Exit a fork but return to parent退出分叉但返回父级
【发布时间】:2017-12-18 14:25:08
【问题描述】:

我第一次尝试使用 fork 时遇到问题。

脚本似乎运行良好,直到我需要它退出 fork 并返回主脚本。

而是完全退出脚本。

my @files = glob( "./input/<Input subnets>.txt" ) or die "Can't open HostInventory$!";     # Open the Host Inventory csv files for parsing

foreach my $file ( @files ) {

    open (CONFIG, '<', $file) or die "Can't <Input subnets>.txt$!";
    my @lines = <CONFIG>;
    chomp (@lines);

    $m = scalar @lines / 10;
    for ( $m ) {
        s/\..*//g
    };

    for ( my $i = 0; $i < @lines; $i += $m ) {

        # take a slice of elements from @files
        my @lines4 = @lines[$i .. $i + $m];

        if ( fork() == 0 ) {

            for my $n ( @lines4 ) {
                system("Nmap -dns-servers <IP of DNS server> -sn -v $n -oX ./input/ip360_DNS/ip360_DNS$n.xml --send-eth --reason");
            }

            exit;  
        }
    }

    wait for 0 .. @lines/$m;
}

此时它应该在父脚本中继续并打开一个解析扫描输出的子例程。相反,它会完全退出脚本。

我做错了什么?

-=-=-=-=更新-=-=-=-= 我尝试了下面的 Parallel::ForkManager 示例。当作为独立进程运行时,它可以完美运行。我在子例程中运行代码,当我尝试这样做时,Perl 解释器崩溃了。有什么建议吗?

#1/usr/bin/perl -w

use Parallel::ForkManager;
use strict;                                             # Best Practice
use warnings;                                           # Best Practice
use Getopt::Long;                                       # Add the ability to use command line options

 if (!@ARGV) {
    &help;
    exit 1
}

GetOptions(
    full =>                 \&full,
    temp =>                 \&temp,
);

                #######################################################################
                #######################################################################
                #                                                                     #
                #                      Call each function                             #
                #                                                                     #
                #######################################################################
                #######################################################################

sub temp {
    &speak;
    &simple;
    &speak2;
    exit;
}

sub full {
    &speak;
    &simple;
    &speak2;
    exit;
}   

sub speak {
    print "This is where I wait for 2 seconds\n";
    sleep (2);
}

my $process = $$;
print "$process\n";

sub simple {

    my $pm = new Parallel::ForkManager(10);
    $pm->run_on_finish(
    sub { $process;
        print "** PID $process\n";
        }
    );

    my @files = glob( "./ping.txt" ) or die "Can't open CMS HostInventory$!";     # Open the CMS Host Inventory csv files for parsing
    foreach my $file (@files){
        open (CONFIG, '<', $file) or die "Can't ip360_DNS File$!";
        my @lines = <CONFIG>;
        chomp (@lines);

        foreach my $n (@lines) {
            # Forks and returns the pid for the child:
            my $pid = $pm->start and next; 

            # ... do some work with $data in the child process ...
            system("ping $n >> ./input/$n.txt");

        }
        $pm->finish; # Terminates the child process
    }
}

sub speak2 {
    print "In new subroutine\n";
}

【问题讨论】:

  • Parallel::ForkManager 会让你的生活更轻松。
  • fork() 创建第二个进程,它是原始进程的精确副本。原件继续运行,副本也继续运行。分叉进程没有“返回”。
  • @Jim Garrison,他们并没有从字面上使用“返回”这个词。他们希望父母等待孩子完成,然后继续执行其他代码。
  • 补充@Jim_Garrison 所说的,你想“使用线程;线程->创建(\&worker_fxn);”而不是 fork() - 谷歌 perl 线程与分叉之间有什么区别。

标签: perl fork


【解决方案1】:

首先,您的脚本不会“完全退出”。它确实等待孩子们完成。或者至少其中一些。你的计算有点偏差。


您正在跳过最后一个元素。

$m = scalar @lines / 10;
for ($m) {s/\..*//g};

等价于

use POSIX qw( floor );

my $m = floor(@lines / 10);

但应该是的

use POSIX qw( ceil );

my $m = ceil(@lines / 10);

你执行了两次边界元素。

my @lines4 = @lines[$i .. $i + $m];

应该是

my @lines4 = @lines[$i .. $i + $m - 1];

wait for 0 .. @lines/$m;

应该是

use POSIX qw( ceil );

wait for 1 .. ceil(@lines/$m);

或者只是

1 while wait > 0;

更容易使用Parallel::ForkManager

use Parallel::ForkManager qw( );

my $pm = Parallel::ForkManager->new(10);  # Max number of children at a time.

$pm->run_on_finish(sub {
   my ($pid, $exit, $id, $signaled, $dumped, $data) = @_;
   my ($config_qfn, $target) = @$id;
   ...
});

for my $config_qfn (glob(...)) {
    open(my $config_fh, '<', $config_qfn)
       or die("Can't open \"$config_qfn\": $!\n");

    chomp( my @targets = <$config_fh> );

    for my $target (@targets) {
        my $pid = $pm->start([$config_qfn, $target])
           and next;

        exec(...)
           or die("exec: $!");
    }
}

$pm->wait_all_children();

顺便说一句,您可能已经注意到我停止了批量操作。这让我可以使用exec 而不是system,这样可以将每个批次的分叉数量减少一个,从而提高不使用批次的效率。

【讨论】:

  • 我尝试了上面的 Parallel::ForkManager 示例。当作为独立进程运行时,它可以完美运行。我在一个子例程中运行代码,当我尝试这样做时,Perl 解释器崩溃了。有什么建议吗?
  • “崩溃”是什么意思?你在 Windows 上吗?
  • 是的,我在 Windows 上。
  • forkexec 在 Windows 上都不存在。它表面上是用线程模拟的,但实际上不是一回事。你最好避免fork!我会使用基于线程的工作池。
猜你喜欢
  • 1970-01-01
  • 2013-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-28
  • 1970-01-01
相关资源
最近更新 更多