doubledecker has asked for the wisdom of the Perl Monks concerning the following question:

Monks

I want to implement Queue mechanism in Perl where in I've a set of 300 jobs in hand and want to run only 3 at a time. I need to regularly check if the processes I've triggered are already running, If so don't start anything new. If any of the process is completed, trigger another process and utmost only 3 processes should run.

Any ideas or suggestions

Replies are listed 'Best First'.
Re: Implement Queue mechanism in Perl
by BrowserUk (Patriarch) on Jan 11, 2011 at 07:15 UTC

    #! perl -slw use strict; use Time::HiRes qw[ sleep ]; use threads; use threads::shared; my @commands = map { my $t = 2+int( rand 5 ); qq[ perl -E"sleep 1 while ++\$n < $t" ]; } 1 .. 300; my $running :shared = 0; my $done :shared = 0; for my $cmd ( @commands ) { async{ ++$running; system $cmd; --$running; ++$done; }->detach; printf( "\r$done, $running" ), sleep 0.1 while $running > 2; }

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Implement Queue mechanism in Perl
by ikegami (Patriarch) on Jan 11, 2011 at 06:43 UTC
Re: Implement Queue mechanism in Perl
by cdarke (Prior) on Jan 11, 2011 at 13:00 UTC
    Another approach is to write a wrapper script (in Perl) to run each job. That wrapper script attempts to claim a semaphore that has a maximum count of 3. The attempt will block if there are 3 (or more) jobs running. After claiming the semaphore the job is run, then (important) it releases the semaphore, which should allow a waiting job to run.

    See perlipc.
Re: Implement Queue mechanism in Perl
by JavaFan (Canon) on Jan 11, 2011 at 13:11 UTC
    A very simple solution is to run three processes in parallel, one process does the first 100 jobs, the second the second 100 jobs, the last the rest of the jobs. It may not be the solution that reaches the fasted time for all jobs to be finished (but that requires solving an NP complete problem anyway - even after knowing in advance how long each job is going to take), but if all jobs take about the same time, the solution may be good enough.
Re: Implement Queue mechanism in Perl
by locked_user sundialsvc4 (Abbot) on Jan 11, 2011 at 17:17 UTC

    Search CPAN.   There are many comprehensive workload management systems available, such as POE.

    You will not have to “reinvent this wheel.”

      Could you show me how to modify this to provide a tasks completed progress indicator per the example above?

      #!/usr/bin/perl use warnings; use strict; use POE qw(Wheel::Run Filter::Reference); sub MAX_CONCURRENT_TASKS () { 3 } my @tasks = qw(one two three four five six seven eight nine ten); POE::Session->create( inline_states => { _start => \&start_tasks, next_task => \&start_tasks, task_result => \&handle_task_result, task_done => \&handle_task_done, task_debug => \&handle_task_debug, sig_child => \&sig_child, } ); sub start_tasks { my ($kernel, $heap) = @_[KERNEL, HEAP]; while (keys(%{$heap->{task}}) < MAX_CONCURRENT_TASKS) { my $next_task = shift @tasks; last unless defined $next_task; print "Starting task for $next_task...\n"; my $task = POE::Wheel::Run->new( Program => sub { do_stuff($next_task) }, StdoutFilter => POE::Filter::Reference->new(), StdoutEvent => "task_result", StderrEvent => "task_debug", CloseEvent => "task_done", ); $heap->{task}->{$task->ID} = $task; $kernel->sig_child($task->PID, "sig_child"); } } sub do_stuff { binmode(STDOUT); # Required for this to work on MSWin32 my $task = shift; my $filter = POE::Filter::Reference->new(); sleep(rand 5); my %result = ( task => $task, status => "seems ok to me", ); my $output = $filter->put([\%result]); print @$output; } sub handle_task_result { my $result = $_[ARG0]; print "Result for $result->{task}: $result->{status}\n"; } sub handle_task_debug { my $result = $_[ARG0]; print "Debug: $result\n"; } sub handle_task_done { my ($kernel, $heap, $task_id) = @_[KERNEL, HEAP, ARG0]; delete $heap->{task}->{$task_id}; $kernel->yield("next_task"); } sub sig_child { my ($heap, $sig, $pid, $exit_val) = @_[HEAP, ARG0, ARG1, ARG2]; my $details = delete $heap->{$pid}; # warn "$$: Child $pid exited"; } $poe_kernel->run(); exit 0;
Re: Implement Queue mechanism in Perl
by moritz (Cardinal) on Jan 12, 2011 at 07:52 UTC

    If all your tasks can be identified by a simple ID, and you are running on Linux, you can "abuse" existing tools:

    $ perl generate_ids.pl | xargs -P 3 -n 1 perl process_single_id.pl