App-Critique

 view release on metacpan or  search on metacpan

lib/App/Critique/Command/collect.pm  view on Meta::CPAN

    }
    else {
        filter_files_parallel( %args );
    }
}

sub filter_files_parallel {
    my %args      = @_;
    my $root      = $args{root}; # the reason for `root` is to pass to the filter
    my $all       = $args{files};
    my $filter    = $args{filter};
    my $num_procs = $args{num_procs};

    my $num_files = scalar( @$all );
    my $temp_dir  = Path::Tiny->tempdir;

    my $partition_size = int($num_files / $num_procs);
    my $remainder      = int($num_files % $num_procs);

    info('Number of files     : %d', $num_files);
    info('Number of processes : %d', $num_procs);
    info('Partition size      : %d', $partition_size);
    info('Remainder           : %d', $remainder);
    info('Total <%5d>       : %d', $num_files, (($partition_size * $num_procs) + $remainder));

    my $pm = Parallel::ForkManager->new(
        $num_procs,
        $temp_dir,
    );

    my @filtered_all;
    $pm->run_on_finish(
        sub {
            my ($pid, $exit_code, $ident, $exit_signal, $core_dump, $data_structure_reference) = @_;
            if ( defined $data_structure_reference ) {
                push @filtered_all => @{ $data_structure_reference };
            }
            else {
                die "Whoa dude, what happened!";
            }
        }
    );

    my @partitions = map {
        [
            (($partition_size * $_) - $partition_size) + (($_ == 1) ? 0 : 1),
            ($partition_size * $_),
        ]
    } 1 .. $num_procs;

    # this will come out to length + 1
    # so we want to trim off the end
    $partitions[ -1 ]->[ 1 ]--;
    # then add the remainder here
    $partitions[ -1 ]->[ 1 ] += $remainder;

PROCESS_LOOP:
    while ( @partitions ) {
        my ($start, $end) = @{ shift @partitions };

        #use Data::Dumper;
        #warn Dumper [ $start, $end ];

        $pm->start and next PROCESS_LOOP;

        my @filtered;

        foreach my $i ( $start .. $end ) {
            my $path = $all->[ $i ];

            info('[%d] Processing file %s', $$, $path);
            if ( $filter->( $root, $path ) ) {
                info(BOLD('[%d] Keeping file %s'), $$, $path);
                push @filtered => $path;
            }
        }

        $pm->finish(0, \@filtered);
    }

    $pm->wait_all_children;

    @$all = @filtered_all;
}

sub filter_files_serially {
    my %args   = @_;
    my $root   = $args{root}; # the reason for `root` is to pass to the filter
    my $all    = $args{files};
    my $filter = $args{filter};

    local $SIG{INT} = sub { $PAUSE_PROCESSING++ };

    my $num_processed = 0;

    my @filtered_all;
    while ( @$all ) {
        if ( $PAUSE_PROCESSING ) {
            warning('[processing paused]');

        PROMPT:
            my $continue = prompt_str(
                '>> (r)esume (h)alt (a)bort | (s)tatus ',
                {
                    valid   => sub { $_[0] =~ m/[rhas]{1}/ },
                    default => 'r',
                }
            );

            if ( $continue eq 'r' ) {
                warning('[resuming]');
                $PAUSE_PROCESSING = 0;
            }
            elsif ( $continue eq 'h' ) {
                warning('[halt processing - retaining results accumulated so far]');
                last;
            }
            elsif ( $continue eq 'a' ) {
                warning('[abort processing - discarding all results]');
                @filtered_all = ();
                last;



( run in 3.538 seconds using v1.01-cache-2.11-cpan-56fb94df46f )