返回介绍

最佳实践 87:多进程编程技巧

发布于 2025-04-20 17:44:52 字数 3507 浏览 0 评论 0 收藏

在本章的前言部分,提到使用 Perl 可以进行多进程编程。如果一个任务涉及大量不同的操作对象,例如批量下载很多 URL 的文件、批量在不同的服务器执行相同的指令等,都可以使用多进程编程。使用多进程编程,可以得到以下好处。

- 最大化服务器执行效率。多进程编程,可以充分利用服务器多 CPU 的计算能力,提高并发执行的数量,减少任务执行的时间。

- 某个子任务超时或者失败不会导致整个任务时间增加。因为使用了多进程,每个进程单独处理一个子任务,这样可以做到隔离子任务间的相互影响,某个子任务的超时和失败,不会影响其他子任务的执行等待时间。

让我们来看一个基本的多进程编程的实例,在该实例中,我们创建 3 个子进程。

#!/u sr/bin/perl
use strict;
use warnings;

print "Process ID: $$";

my $maxforks = 3;
my $forks    = 0;
for ( 1 .. $maxforks ) {
    my $pid = fork;#父进程调用 fork 函数,函数参考 perldoc -f fork
    if ( not defined $pid ) { #fork 返回 undef,则说明创建子进程失败,例如在超过了系统最大进程数等的情况下
        warn 'Could not fork';
        next;
    }
    if ($pid) { #fork 对父进程的返回值是子进程的进程号(pid)
        $forks++;
        print
          "In the parent process PID ($$), Child pid: $pid Num of fork child processes: $forks \n";
    }
    else {#进入子进程执行代码
        print "In the child process PID ($$) \n";
        sleep 1;
        print "Child ($$) exiting \n";
        exit;
    }
}

for ( 1 .. $forks ) {
    my $pid = wait();#wait 函数返回值为已完成执行的子进程的进程号(pid),函数参考 perldoc -f wait
    print "Parent saw $pid exiting \n";
}
print "Parent ($$) ending \n";

在上面的一个案例中,使用 fork 进行子进程创建,然后在程序内部进行了子进程的管理(创建数量限制、子进程退出状态管理等)。可以看到,这样操作起来比较繁杂。幸运的是,在 Perl 中,通过 CPAN,可以下载和使用 Parallel::ForkManager 模块进行多进程自动化管理。在下面一个例子中,使用该模块同时启动 30 个子进程登录服务器拷贝指定文件保存到对应的指定文件夹中。

#!perl
use strict;
use warnings;
use Parallel::ForkManager;

sub convert {
    my ($in) = @_;
    $in =~ s/\//./g;
    $in =~ s/\:/../g;
    return $in;
}
my $xiv       = $ARGV[0];
my $inputfile = 'hosts_' . $xiv . '_all.dat';

open( FILEIN, '<', $inputfile ) or die $!;
my $pm = Parallel::ForkManager->new(30); #指定同时执行的子进程的数量上限是 30
while (<FILEIN>) {
  #输入的文件内容格式如下
    #10.18.33.130     xiv3-nj-p001     180.96.46.70
    chomp;
    my $host;
    if (/^([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\s+(.*)/) {
        $host = $1;
    }
    $pm->start and next;#创建的子进程进入执行周期
    my @files = (
        '/bin/iptables.sh',
        '/etc/fstab',
        '/etc/group',
        '/etc/hosts',
        '/etc/hosts.allow',
        '/etc/modprobe.conf',
        '/etc/ntp.conf',
        '/etc/passwd',
        '/etc/rc.local',
        '/etc/rc.d/rc.local',
        '/etc/shadow',
        '/etc/snmp/snmpd.conf',
        '/etc/sudoers',
        '/etc/sysconfig/network',
        '/etc/sysconfig/network-scripts/ifcfg-bondeth1',
        '/etc/sysconfig/network-scripts/ifcfg-eth0',
        '/etc/sysconfig/network-scripts/ifcfg-eth1',
        '/etc/sysconfig/network-scripts/ifcfg-lo:0',
        '/etc/sysconfig/static-routes',
        '/etc/sysctl.conf',
        '/etc/yum.conf',
        '/etc/yum.repos.d/CentOS-Base.repo',
        '/root/.bashrc',
        '/root/.ssh/authorized_keys',
        '/root/iptables_min_forFF14.sh',
        '/tmp/__pcheck.chkconfig3on.txt',
        '/tmp/__pcheck.rpm.txt',
        '/tmp/__pcheck.sysctl-A.txt'

    );
    system("ssh root\@$host 'rpm -qa |sort > /tmp/__pcheck.rpm.txt'");
    system("ssh root\@$host 'sysctl -A |sort > /tmp/__pcheck.sysctl-A.txt'");
    system("ssh root\@$host 'chkconfig --list|grep '3:on'|sort > /tmp/__pcheck.chkconfig3on.txt'");
    foreach my $file (@files) {
        my $converted = &convert($file);
        system("mkdir -p /tmp/checklog/$xiv/$converted/");
        system("scp root\@$host:$file /tmp/checklog/$xiv/$converted/$host.txt");
    }

    $pm->finish;#结束子进程执行
}
close(FILEIN); #父进程关闭文件描述符
$pm->wait_all_children;#等待所有子进程执行完成

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。