1

I am trying to get an idea of how to implement async (parallel) function call in Perl (in one of my Mojolicious controllers to process lots of data sets).

Here is what I have (a simple example):

use Future::AsyncAwait;

async sub asyncSub{
    
    async sub funcA{
        my $num = shift;
        print "This is $num (START)\n";
        sleep 1;
        print "This is $num (END)\n";
    };

    funcA(1);
    funcA(2);
    funcA(4);
    funcA(5);
    funcA(6);
    funcA(7);
    funcA(8);
    funcA(9);
    funcA(10);

}

asyncSub();

This code prints out:

This is 1 (START)
This is 1 (END)
This is 2 (START)
This is 2 (END)
This is 4 (START)
This is 4 (END)
This is 5 (START)
This is 5 (END)
This is 6 (START)
This is 6 (END)
This is 7 (START)
This is 7 (END)
This is 8 (START)
This is 8 (END)
This is 9 (START)
This is 9 (END)
This is 10 (START)
This is 10 (END)

It always works synchronously.

Thank you in advance for your help.

Arsenii
  • 655
  • 1
  • 8
  • 20

2 Answers2

2

Yes indeed. sleep is always synchronous. You did not make any asynchronous calls, so your code isn't asynchronous.

Future::AsyncAwait is not a multi-tasking system. It doesn't provide asynchronousness. Futures are similar to JavaScript promises and even more so to .NET tasks. They provide a means of working with asynchronous calls more easily. But you still have to make asynchronous calls to have asynchronousness.

You'd have the same problem in C# if you used Thread.Sleep( 1000 ) (synchronous) instead of await Task.Delay( 1000 ); (asynchronous).

ikegami
  • 367,544
  • 15
  • 269
  • 518
  • Looks like Parallel.ForEach provides multithreading, not asynchronousness – ikegami Mar 24 '23 at 17:24
  • And no, there are many async and multi-tasking systems. I can't pick one for you. You didn't even provide any information that would be useful in helping decide. – ikegami Mar 24 '23 at 17:32
0

You will need an async framework to be able to run async code. You mentioned Mojolicious, which itself includes support for async/await. The code below is an example of sleeping using a Mojo::Promise->timer(). I've also included an alternative sub that uses Mojo::IOLoop::Subprocess, which runs in a forked process and can therefore run functions which would otherwise be blocking. However, this has the overhead of starting a new process.

use strict;
use warnings;
use Mojo::Base -async_await;
use Mojo::Promise;
use Mojo::IOLoop::Subprocess;

async sub asyncSub {
    my @promises = map { funcA($_) } (1..3);
    await Mojo::Promise->all(@promises);
}

async sub funcA {
    my $num = shift;
    print "This is $num (START)\n";
    await Mojo::Promise->timer(1);
    print "This is $num (END)\n";
};

async sub funcB {
    my $num = shift;
    my $subprocess = Mojo::IOLoop::Subprocess->new;
    print "Subprocess $num (START)\n";
    await $subprocess->run_p( sub {
        sleep(1);
    });
    print "Subprocess $num (END)\n";
    return;
};


await asyncSub();
bscan
  • 2,816
  • 1
  • 16
  • 16