Concurrency

37.1 Parallel Processes

use Parallel::ForkManager;             # CPAN: simple worker pool
my $pm = Parallel::ForkManager->new(4);
$pm->run_on_finish(sub { my ($pid, $exit, $ident, $signal, $core, $data) = @_; say "$ident done: $$data" });
for my $url (@urls) {
    $pm->start($url) and next;         # parent continues; the child runs below
    my $result = fetch($url);
    $pm->finish(0, \$result);          # send data back to the parent
}
$pm->wait_all_children;
# Also: MCE (Many-Core Engine: parallel map/grep/loops), Parallel::Prefork
use MCE::Map;
my @squares = mce_map { $_ * $_ } 1..1_000_000;

37.2 Threads (ithreads)

Perl ithreads copy the whole interpreter per thread (heavy). They require a thread-enabled build (perl -V:useithreads). The Perl documentation discourages them for most uses: prefer processes or event loops.

use threads;
use threads::shared;
use Thread::Queue;

my $counter :shared = 0;
my $q = Thread::Queue->new(1..20);
$q->end;
my @workers = map {
    threads->create(sub {
        while (defined(my $item = $q->dequeue)) {
            lock($counter);
            $counter += $item;
        }
    });
} 1..4;
$_->join for @workers;
say $counter;                          # 210

37.3 Event Loops and Async I/O

Others: AnyEvent (a common event API), POE (classic), Coro (coroutines; not maintained for newer Perls).

# Mojolicious: non-blocking I/O with promises and async/await
use Mojo::Base -strict, -signatures, -async_await;
use Mojo::UserAgent;
my $ua = Mojo::UserAgent->new;

async sub fetch_titles(@urls) {
    my @tx = await Mojo::Promise->all(map { $ua->get_p($_) } @urls);
    return map { $_->[0]->result->dom->at('title')->text } @tx;
}
fetch_titles('https://perl.org', 'https://metacpan.org')->then(sub { say for @_ })->wait;
# Future + IO::Async (and Future::AsyncAwait: async/await keywords)
use v5.36;
use Future::AsyncAwait;
use IO::Async::Loop;
use Net::Async::HTTP;
my $loop = IO::Async::Loop->new;
my $http = Net::Async::HTTP->new; $loop->add($http);
async sub get_status($url) { my $resp = await $http->GET($url); return $resp->code }
say get_status('https://www.perl.org')->get;    # ->get blocks until the Future completes