Reputation: 23
I am fairly new to Perl and I am trying to achieve the following:
sub foo {
my $serviceRespone = makeSomeServiceCall();
doSomeExpensiveOperationWhoseResultWeDontCareAbout($serviceResponse); # Should not block execution and run in background
return $serviceResponse;
}
Is there any built-in functions and/or libraries that can help me fire-and-forget an action and improve latency, like the line I added the comment with? Thanks in advance!
Upvotes: 2
Views: 1042
Reputation: 195
Here is how I would use the threads
module for the code sample posted in your question:
use threads; # The threads module will be needed
sub foo {
my $serviceResponse = makeSomeServiceCall();
# Here, the thread is created, the code ref of the code to run is passed in
# in as the first parameter. All the remaining parameters are passed to the
# ref'd code as parameters
my $thrd = threads->create(
\&doSomeExpensiveOperationWhoseResultWeDontCareAbout, $serviceResponse
);
# Detach the thread since we don't care about the result. Detached
# threads will silently terminate when the program exits.
$thrd->detach;
return $serviceResponse;
}
# Here, you define the function you don't want to wait for.
sub doSomeExpensiveOperationWhoseResultWeDontCareAbout {
my ( $serviceResponse ) = @_;
# Do stuff ...
}
Note that the threads
module is built-in.
Upvotes: 0
Reputation: 11
You can also use threads:
use threads; sub expensiveop { [...] } sub foo { my $thr = threads->create(\&expensiveop); my $serviceRespone = makeSomeServiceCall(); return $serviceResponse; } [...] $thr->join(); # wait for thread to finish if you care
Upvotes: 1
Reputation: 6798
I use following piece of code to run tasks in parallel asynchronously
#!/usr/bin/perl
#
# USAGE:
# prog.pl
#
# Description:
# Demonstration how to run asynchronous processes
# in parallel (threaded application)
#
# StackOverflow:
# Question 60022665
#
# Author:
# Polar Bear https://stackoverflow.com/users/12313309/polar-bear
#
# Date: Tue Feb 1 19:55:00 PST 2020
#
use strict;
use warnings;
use feature 'say';
use POSIX ":sys_wait_h"; # WNOHANG definition for waitpid
use Time::HiRes qw(usleep); # We will use usleep when all workers busy
my $tasks = 1000; # total number of tasks to run
my $workers = 5; # number of available workers
sub REAPER { # $SIG{CHLD} exit handler
while ((my $kid = waitpid(-1, &WNOHANG)) > 0) { # to avoid zombie
say "Process: $kid done"; # worker finished it's work
$workers++; # increment number of available workers
}
$SIG{CHLD} = \&REAPER; # Attach $SIG{CHLD} to handler
}
$SIG{CHLD} = \&REAPER; # Attach $SIG{CHLD} to handler
while( $tasks ) { # while there are tasks to run
while( $workers == 0 ) { usleep(1) } # while all workers busy take a nap
my $pid = fork();
die "cannot fork" unless defined $pid;
if( $pid == 0 ) { # child process
worker($arg); # worker started
exit; # IMPORTANT: worker must exit to signal REAPER
} else { # parent process
$tasks--; # decrement numbers of tasks to run
$workers--; # decrement number of available workers
}
}
exit 0; # all processes has finished their work
sub worker { # worker process
my $arg = shift;
say "Started process $$ with argument $arg";
sleep( rand(20) ); # simulate process work
}
NOTE: please read documentation for fork and waitpid about limits and portability. See documentation perlipc for more examples.
Upvotes: 3
Reputation: 118595
If you don't care about the result of the long-running operation, builtin fork
is sufficient
if (fork() == 0) {
# child process
doSomeExpensiveOperationWhoseResultWeDontCareAbout($serviceResponse);
exit;
}
# parent process continues ...
Upvotes: 2