perlasynchronous

Asynchronous programming in Perl


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!


Solution

  • 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.