Асинхронное программирование в Perl - PullRequest
2 голосов
/ 02 февраля 2020

Я довольно плохо знаком с Perl и пытаюсь добиться следующего:

sub foo {
    my $serviceRespone = makeSomeServiceCall();
    doSomeExpensiveOperationWhoseResultWeDontCareAbout($serviceResponse); # Should not block execution and run in background
    return $serviceResponse;
}

Существуют ли какие-либо встроенные функции и / или библиотеки, которые могут мне помочь? запустить и забыть действие и улучшить задержку, как в строке, к которой я добавил комментарий? Заранее спасибо!

Ответы [ 3 ]

3 голосов
/ 02 февраля 2020

Я использую следующий фрагмент кода для асинхронного параллельного выполнения задач

#!/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
}

ПРИМЕЧАНИЕ: пожалуйста, прочитайте документацию для fork и waitpid об ограничениях и переносимости. См. Документацию perlip c для дополнительных примеров.

2 голосов
/ 02 февраля 2020

Если вас не волнует результат длительной операции, достаточно встроенного fork

if (fork() == 0) {
    # child process
    doSomeExpensiveOperationWhoseResultWeDontCareAbout($serviceResponse);
    exit;
}
# parent process continues ...
1 голос
/ 12 февраля 2020

Вы также можете использовать темы:

    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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...