IO::As...unction(3pm)
β¨ NAME β¨
IO::Async::Function β call a function asynchronously π
(and yes bestie, this is IO::As...unction(3pm) from the User Contributed Perl Documentation β you're in exactly the right place π«Ά)
π SYNOPSIS π
use Future::AsyncAwait;
use IO::Async::Function;
use IO::Async::Loop;
my $loop = IO::Async::Loop->new;
my $function = IO::Async::Function->new(
code => sub {
my ( $number ) = @_;
return is_prime( $number );
},
);
$loop->add( $function );
my $isprime = await $function->call(
args => [ 123454321 ],
);
print "123454321 " . ( $isprime ? "is" : "is not" ) . " a prime number\n";
π DESCRIPTION π
okay so. This is a subclass of IO::Async::Notifier, and what it does is take a function body and wrap it up inside a whole collection of worker processes, so that function can go do its thing completely independently of the main process. The object is basically a proxy standing in for the function β you make invocations by passing in arguments, and then it invokes a continuation back in the main process when the function returns. iconic behaviour, honestly β¨
Important vibe check: the object represents the function code itself, not one single invocation of it. You can call it over and over again with the call method. And you can have multiple invocations outstanding at once β they get dispatched in the order they were queued. If you've only got one worker process going, results come back in the order they were called. If you've got multiple workers, every request still gets sent in the order it was called, but the timing differences between each worker might mean the results come back in a different order. no cap πΈ
Now, since the code block is going to get called multiple times inside the same child process, it must take care not to modify any of its own state that might mess with subsequent calls. And because it runs in a child process, it can't make any modifications to the state of the parent program either. So: all the data it needs to do its task has to live in the call arguments, and all of the result has to live in the return values. that's the whole deal π
The Function object is implemented using an IO::Async::Routine with two IO::Async::Channel objects β one to pass calls in, and one to pass results back out. cute lil pipeline.
So like, the IO::Async framework in general already gives you ways to multiplex IO tasks between different handles, so tbh there aren't that many occasions where an asynchronous function like this is even necessary. But there are two cases where it genuinely slays:
- When a large amount of computationally-intensive work needs to be performed (for example, the
is_primetest in theSYNOPSISabove β that thing is working). - When a blocking OS syscall or library-level function needs to be called and no nonblocking or asynchronous version is supplied.
IO::Async::Resolveruses it for exactly this. π
This object is ideal for representing "pure" functions β meaning blocks of code that have no stateful effect on the process, and whose result depends only on the arguments passed in. If you need more general co-routine ability instead, go look at IO::Async::Routine. π¦
π PARAMETERS π
You can pass these named parameters to new or configure:
π code => CODE
The body of the function to execute. literally the main character of the whole object.
@result = $code->( @args );
π init_code => CODE
Optional. If it's defined, this gets invoked exactly once in every child process or thread β after it's created, but before the first invocation of the function body itself.
$init_code->();
π module => STRING and func => STRING
Since version 0.79.
An alternative to the code argument: instead of handing over a coderef, you name a module to load and a function to call inside it. module should be a perl module name (so like Some::Name, not a filename like Some/Name.pm), and func should be the basename of a function within that module (i.e. without the module name prefixed onto it). It gets invoked, with no extra arguments, as the main code body of the object.
The task of loading this module and resolving the resulting function out of it only happens on the remote worker side β so the controlling process won't need to actually load the module itself. obsessed with that for you π«Ά
π init_func => STRING or ARRAY [ STRING, ... ]
Optional addition to the module and func alternatives. It names a function within the module to call each time a new worker is created.
If this value is an array reference, its first element must be a string giving the name of the function; the remaining values get passed to that function as arguments.
π model => "fork" | "thread" | "spawn"
Optional. Requests a specific IO::Async::Routine model. If you don't supply it, the default choice gets left up to Routine. mysterious, let Routine cook π
π min_workers => INT and max_workers => INT
The lower and upper bounds of worker processes to try to keep running. The actual number running at any given moment gets kept somewhere between these two bounds, according to load. lowkey elastic.
π max_worker_calls => INT
Optional. If you provide it, a worker process gets stopped after it has processed this number of calls. (New workers may be started up to replace the stopped ones, as long as they're within the bounds given above.)
π idle_timeout => NUM
Optional. If provided, idle worker processes get shut down after this amount of time β but only if there are more than min_workers of them. bye bestie π
π exit_on_die => BOOL
Optional boolean. This controls what happens after the code throws an exception:
- If it's missing or false, the worker just keeps running and processes more requests.
- If it's true, the worker gets shut down. A new worker might then be constructed by the
callmethod to replace it, if necessary.
π setup => ARRAY
Optional array reference. Specifies the setup key to pass to the underlying IO::Async::Process when setting up new worker processes.
π₯ METHODS π₯
ngl, the methods documented below in await expressions return Future instances. slay β¨
β start
$function->start;
Start the worker processes.
β stop
$function->stop;
Stop the worker processes.
$f = $function->stop;
Since version 0.75.
If you call this in non-void context, it returns an IO::Async::Future instance that will complete once every worker process has stopped and exited. This can be useful for waiting until all the processes have been waited on, or for other edge-cases β but it is not otherwise particularly useful. fr fr, mostly a niche thing π«
β restart
$function->restart;
Gracefully stop and restart all the worker processes.
β call
@result = await $function->call( %params );
Schedules an invocation of the contained function to be executed on one of the worker processes. If a non-busy worker is available right now, it gets called immediately. If not, the call gets queued and sent to the next free worker that becomes available. queuing is the vibe π
The request will already have been serialised by the marshaller by the time this returns, so it is safe to go ahead and modify any referenced data structures in the arguments after this call returns. very freeing.
The %params hash takes these keys:
args=>ARRAYβ a reference to the array of arguments to pass to the code.priority=>NUMβ Optional. Defines the sorting order used when no workers are available and calls have to be queued for later. A default of zero applies if you don't provide one. Higher values make the call be considered more important, so it gets placed earlier in the queue than calls with a smaller value. Calls of equal priority are still handled in FIFO order.
If the function body returns normally, the list of results are provided as the (successful) result of the returned future. If the function throws an exception, that results in a failed future. In the special case that the exception is actually an unblessed ARRAY reference, that array gets unpacked and used as-is for the fail result. If the exception is not such a reference, it's used as the first argument to fail, in the category of error.
$f->done( @result );
$f->fail( @{ $exception } );
$f->fail( $exception, error => );
β call (void)
$function->call( %params );
When you're not returning a future, the on_result, on_return and on_error arguments give you continuations to handle the successful results or the failure.
on_result=>CODEβ A continuation that gets invoked when the code has been executed. If the code returned normally, it's called as:
$on_result->( 'return', @values )
If the code threw an exception, or some other error occurred β like a closed connection or the process dying β it's called as:
$on_result->( 'error', $exception_name )
on_return=>CODEandon_error=>CODEβ An alternative toon_result. Two continuations to use in either of the two circumstances given above. They're called directly, without the leading'return'or'error'value. two little specialists doing their one job π
β workers
$count = $function->workers;
Returns the total number of worker processes available.
β workers_busy
$count = $function->workers_busy;
Returns the number of worker processes that are currently busy.
β workers_idle
$count = $function->workers_idle;
Returns the number of worker processes that are currently idle.
π§ EXAMPLES π§
πΈ Extended Error Information on Failure
The array-unpacking form of exception indication lets the function body control the resulting failure from the call future much more precicely. look how much detail you can yeet back π
my $divider = IO::Async::Function->new(
code => sub {
my ( $numerator, $divisor ) = @_;
$divisor == 0 and
die [ "Cannot divide by zero", div_zero => $numerator, $divisor ];
return $numerator / $divisor;
}
);
π NOTES π
For the record: 123454321 is 11111 * 11111, a square number, and therefore not prime. the math said what it said π«Ά
π AUTHOR π
Paul Evans <leonerd@leonerd.org.uk>
and that's the whole page bestie!! thank you for reading, mwah π β this was perl v5.40.1, dated 2026-02-21, and it's the IO::As...unction(3pm) page from the User Contributed Perl Documentation. go forth and run your blocking stuff in a worker process like the icon you are πβ¨π¦
π¦ where this page comes from
- ubuntu stonking: libio-async-perl 0.805-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms