Worker Pools in Perl
Our example demonstrates how to implement a worker pool using threads and queues in Perl.
use strict;
use warnings;
use threads;
use Thread::Queue;
use Time::HiRes qw(sleep);
# This is the worker subroutine. We'll run several concurrent instances of it.
# These workers will receive work on the $jobs queue and send the corresponding
# results on $results. We'll sleep a second per job to simulate an expensive task.
sub worker {
my ($id, $jobs, $results) = @_;
while (defined(my $job = $jobs->dequeue())) {
print "worker $id started job $job\n";
sleep(1);
print "worker $id finished job $job\n";
$results->enqueue($job * 2);
}
}
# In the main function, we set up our worker pool
sub main {
my $num_jobs = 5;
my $jobs = Thread::Queue->new();
my $results = Thread::Queue->new();
# This starts up 3 workers, initially blocked because there are no jobs yet.
my @workers;
for my $w (1..3) {
push @workers, threads->create(\&worker, $w, $jobs, $results);
}
# Here we send 5 jobs and then signal that's all the work we have.
for my $j (1..$num_jobs) {
$jobs->enqueue($j);
}
$jobs->end();
# Finally we collect all the results of the work.
# This also ensures that the worker threads have finished.
for (1..$num_jobs) {
my $result = $results->dequeue();
}
# Wait for all worker threads to finish
$_->join() for @workers;
}
main();
Our running program shows the 5 jobs being executed by various workers. The program only takes about 2 seconds despite doing about 5 seconds of total work because there are 3 workers operating concurrently.
$ perl worker_pools.pl
worker 1 started job 1
worker 2 started job 2
worker 3 started job 3
worker 1 finished job 1
worker 1 started job 4
worker 2 finished job 2
worker 2 started job 5
worker 3 finished job 3
worker 1 finished job 4
worker 2 finished job 5
real 0m2.052s
This example demonstrates how to use Perl’s threading capabilities to create a worker pool. It uses the threads
module for creating threads and the Thread::Queue
module for inter-thread communication.
The worker
subroutine represents each worker in the pool. It continuously dequeues jobs from the $jobs
queue, processes them (simulated by a 1-second sleep), and enqueues the results to the $results
queue.
In the main
subroutine, we create the job and result queues, spawn three worker threads, distribute five jobs among them, and then collect the results.
Note that Perl’s threading model is different from some other languages. Perl threads are relatively heavyweight, and for many concurrent tasks, other solutions like event loops or forking might be more appropriate. However, this example serves to illustrate the concept of worker pools in a Perl context.