NAME
EV::Future - Minimalist high-performance async control flow for EV
SYNOPSIS
use EV;
use EV::Future;
my @w;
parallel([
sub { my $done = shift; push @w, EV::timer 0.1, 0, sub { $done->() } },
sub { my $done = shift; push @w, EV::timer 0.2, 0, sub { $done->() } },
], sub { print "all done\n" });
parallel_limit([
sub { my $done = shift; push @w, EV::timer 0.1, 0, sub { $done->() } },
sub { my $done = shift; push @w, EV::timer 0.2, 0, sub { $done->() } },
sub { my $done = shift; push @w, EV::timer 0.1, 0, sub { $done->() } },
], 2, sub { print "all done (max 2 in-flight)\n" });
series([
sub { my $done = shift; $done->() },
sub { my $done = shift; $done->() },
], sub { print "all done in order\n" });
EV::run;
DESCRIPTION
Three control-flow primitives (parallel, parallel_limit, series), implemented in XS for minimal overhead. All three are exported by default.
Each task is a coderef that receives a single done callback as its only argument; the task must invoke done exactly once to mark completion.
If \@tasks is empty, final_cb fires immediately. Non-coderef elements in \@tasks are treated as no-op tasks that complete instantly.
Safe vs unsafe mode
Each function takes an optional trailing $unsafe flag. In safe mode (the default), each dispatch is wrapped in G_EVAL, every task gets its own done CV, and double-calls are silently dropped. Unsafe mode skips G_EVAL and reuses a single shared CV, roughly doubling throughput at the cost of:
Exceptions from a task bypass cleanup and leak the internal context.
Double-calling
donecorrupts the completion counter, which may invokefinal_cbbefore all tasks have actually finished.
Use unsafe mode only when tasks are well-behaved and performance is critical.
FUNCTIONS
parallel(\@tasks, \&final_cb, [$unsafe])
Dispatch every task immediately; call final_cb once each task has invoked its done callback.
parallel_limit(\@tasks, $limit, \&final_cb, [$unsafe])
Dispatch tasks with at most $limit in flight at any time. $limit is clamped to 1..scalar(@tasks): $limit == 1 degenerates to series, $limit >= @tasks degenerates to parallel.
There is no cancellation mechanism — all dispatched tasks must complete. The truthy-done cancellation supported by series does not apply here.
series(\@tasks, \&final_cb, [$unsafe])
Run tasks sequentially; each task starts only after the previous calls its done. To cancel the series and skip remaining tasks, pass a true value to done:
series([
sub { my $d = shift; $d->(1) }, # cancel here
sub { die "never reached" },
], sub { print "finished early\n" });
Cancellation works in both safe and unsafe modes.
BENCHMARKS
1000 synchronous tasks, 5000 iterations (bench/benchmark.pl):
--- PARALLEL (iterations/sec) ---
EV::Future (unsafe) 4,386
EV::Future (safe) 2,262
AnyEvent::cv (begin/end) 1,027
Future::XS::wait_all 982
Promise::XS::all 32
--- PARALLEL LIMIT 10 (iterations/sec) ---
EV::Future (unsafe) 4,673
EV::Future (safe) 2,688
Future::Utils::fmap_void 431
--- SERIES (iterations/sec) ---
EV::Future (unsafe) 5,000
AnyEvent::cv (stack-safe) 3,185
EV::Future (safe) 2,591
Future::XS (chain) 893
Promise::XS (chain) 809
SEE ALSO
AUTHOR
vividsnow
LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 92:
Non-ASCII character seen before =encoding in '—'. Assuming UTF-8