menu

Perl Mr.How知其所以然之perl代码模板

Perl Mr.How知其所以然之perl代码模板

原创文章,版权所有,搬运文章,转发请注明polyaD,原文链接https://polyad.github.io/tags
如有任何问题或疑惑,请在后面留言或者发邮箱留言polyaluthor@gmail.com,加微信polyad或者qq数学算法开发10群 282642152进行探讨,请备注:Mr.How。


  • 理念
  • 逻辑大纲
    • 1.背景信息:作者,联系方式,更新时间,版本,主要功能,主要实现逻辑,使用示例,运行方法
    • 2.主程序:包含的标准库信息,perl模板,函数功能实现,主程序,调用处理信息
    • 3.次模块:外部参数输入模块,时间运行模块,输出模块,输入检测模块,检测模块,测试模块
    • 4.数据如何有序安全传递?数据如何存储并处理?
    • 5.问题列表
#!/usr/bin/env perl
use strict;
use warnings;
use FindBin;
use Getopt::Long qw(:config no_ignore_case bundling);
use List::Util qw (shuffle);
my $usage = <<_EOUSAGE_;
###########################################################################################
#
#  -c <string>     filename containing a list of commands to execute, one cmd per line.
#
#  --CPU           Default: 1
#
#  --shuffle       randomly orders the commands before executing them.
#
###########################################################################################
_EOUSAGE_

my $cmds_file;
my $CPU = 1;
my $shuffle_flag = 0;

&GetOptions (
             "c=s" => \$cmds_file,
             "CPU=i" => \$CPU,
             "shuffle" => \$shuffle_flag,
             );

unless ($cmds_file) {
    die $usage;
}

my $log_dir = "cmds_log.$$";
mkdir($log_dir) or die "Error, cannot mkdir $log_dir";

## This is very cheap 'parallel-computing' !!!  :)

my $uname = `uname -n`;
chomp $uname;

print "SERVER: $uname, PID: $$\n";

my $ENCOUNTERED_FAILURE = 0;

main: {

    my %job_tracker;
    my @failed_jobs;
    my $num_running = 0;

    ########### just command strings such as you would launch directly from a bash shell.
    my @unix_cmds;

    ########### list of completed commands
    my %completed_cmds = ();

    my $completed_file_name = $cmds_file.".completed";

    {
        ######## process list of completed commands
        if(-f ($completed_file_name)){
            open (my $fh, "<", $completed_file_name) or die "Error, cannot open completion file for reading $completed_file_name";
            while (<$fh>) {
                chomp;
                $completed_cmds{$_} = 1;
            }
        }

        ######## load all commands in memory... filesystem glitches can otherwise result in premature termination with inadvertent success status.
        open (my $fh, $cmds_file) or die "Error, cannot open file $cmds_file";
        while (my $cmd = <$fh>) {
            chomp $cmd;
            if(!$completed_cmds{$cmd}){
                push (@unix_cmds, $cmd);
            }
        }
        close $fh;
    }

    if ($shuffle_flag) {
        @unix_cmds = shuffle(@unix_cmds);
    }

    my $cmd_counter = 0;
    foreach my $cmd (@unix_cmds) {
        $cmd_counter++;
        $num_running++;
        my $child = fork();

        if ($child) {
            ######### parent
            $job_tracker{$cmd_counter} = $cmd;
        }
        else {
            ######### child:
            my $ret = &run_cmd($cmd_counter, $cmd);
            exit($ret);
        }

        if ($num_running >= $CPU) {
            wait();
            my $num_finished = &collect_jobs(\%job_tracker, \@failed_jobs, $completed_file_name);
            $num_running -= $num_finished;

            ####### collect the other finished children to avoid build-up of zombie processes.
            for (1..$num_finished-1) {
                wait();
            }
        }
    }

    ##### collect remaining processes.
    while (wait() != -1) { };

    &collect_jobs(\%job_tracker, \@failed_jobs, $completed_file_name);

    ##### purge log directory
    `rm -rf $log_dir`;

    my $num_failed_jobs = scalar @failed_jobs;
    if (! $ENCOUNTERED_FAILURE) {
        print "\n\nAll $cmd_counter jobs completed successfully! :) \n\n";
        exit(0);
    }
    else {
        unless ($num_failed_jobs == $ENCOUNTERED_FAILURE) {
            print "\n\nError, $ENCOUNTERED_FAILURE jobs failed, but only have recorded $num_failed_jobs ... very strange and unexplained.\n\n";
            ###### I haven't seen this in my testing, but it's clear that others have, and I haven't figured out why or how yet...  bhaas
        }

        ###### write all failed commands to a file.
        my $failed_cmd_file = "failed_cmds.$$.txt";
        open (my $ofh, ">$failed_cmd_file") or die "Error, cannot write to $failed_cmd_file";
        @failed_jobs = sort {$a->{index}<=>$b->{index}} @failed_jobs;
        foreach my $failed_job (@failed_jobs) {
            print $ofh $failed_job->{cmd} . "\n";
        }
        close $ofh;

        print "\n\nSorry, $num_failed_jobs of $cmd_counter jobs failed.\n\n"
            . "Failed commands written to file: $failed_cmd_file\n\n";
        exit(1);
    }
}

##################################
sub run_cmd {
    my ($index, $cmd) = @_;
    print "\nRUNNING: $cmd\n";
    my $ret = system($cmd);

    if ($ret) {
        print STDERR "Error, command: $cmd died with ret $ret";
    }
    open (my $log_fh, ">$log_dir/$index.ret") or die "Error, cannot write to log file for $index.ret";
    print $log_fh $ret;
    close $log_fh;
    return($ret);
}
##################################
sub collect_jobs {
    my ($job_tracker_href, $failed_jobs_aref, $completed_file) = @_;

    my @job_indices = keys %$job_tracker_href;

    my $num_finished = 0;

    foreach my $index (@job_indices) {

        my $log_file = "$log_dir/$index.ret";

        if (-s $log_file) {
            my $ret_val = `cat $log_file`;
            chomp $ret_val;
            my $job = $job_tracker_href->{$index};
            if ($ret_val == 0) {

                ##### hurray, job succeded.
                print "SUCCESS[$index]: $job\n";

                ##### write completed jobs to file
                if(open (my $fh, ">>", $completed_file)){
                    print($fh $job."\n");
                    close($fh);
                }
            } else {
                ##### job failed.
                print "FAILED[$index]: $job\n";
                $ENCOUNTERED_FAILURE++;
                push (@$failed_jobs_aref, {index => $index,
                                           cmd => $job_tracker_href->{$index},
                                          });
            }
            unlink $log_file;
            $num_finished++;
            ##### job done, no need to continue tracking it. (thanks Raj!)
            delete $job_tracker_href->{$index};
        }
    }
    return($num_finished);
}



返回顶部



评论:


技术文章推送

知其所以然主题模块分享

微信搜索公众号: How先生polyad
wechat 微信公众号:How先生polyad