NAME
EV::Future - Minimalist and high-performance async control flow for EV
SYNOPSIS
use EV;
use EV::Future;
my @watchers;
EV::Future::parallel([
sub { my $done = shift; push @watchers, EV::timer 0.1, 0, sub { print "Task 1 done\n"; $done->() } },
sub { my $done = shift; push @watchers, EV::timer 0.2, 0, sub { print "Task 2 done\n"; $done->() } },
], sub {
print "All parallel tasks finished\n";
});
EV::Future::parallel_limit([
sub { my $done = shift; push @watchers, EV::timer 0.1, 0, sub { print "Task A\n"; $done->() } },
sub { my $done = shift; push @watchers, EV::timer 0.2, 0, sub { print "Task B\n"; $done->() } },
sub { my $done = shift; push @watchers, EV::timer 0.1, 0, sub { print "Task C\n"; $done->() } },
], 2, sub {
print "All limited-parallel tasks finished\n";
});
EV::Future::series([
sub { my $done = shift; print "Task 1 start\n"; $done->() },
sub { my $done = shift; print "Task 2 start\n"; $done->() },
], sub {
print "All series tasks finished\n";
});
EV::run;
DESCRIPTION
Focuses on performance and minimalism, offloading task management to XS.
TASKS
Each task is a coderef that receives a single argument: a "done" callback. The task MUST call this callback exactly once when it is finished.
Exceptions
If a task throws an exception (e.g., via die), the exception will be propagated immediately. EV::Future ensures that internal memory is cleaned up correctly in this case.
Double-calls
Calling the done callback more than once for a single task is considered incorrect usage. In safe mode (the default), EV::Future prevents catastrophic failure:
In
parallelandparallel_limit, extra calls to a specificdonecallback are silently ignored.In
series, extra calls to a specificdonecallback are ignored. Only thedonecallback provided to the currently active task can advance the series.
In unsafe mode, these protections are not active. Double-calls will corrupt the internal completion counter, which may cause final_cb to be invoked multiple times or trigger use-after-free.
FUNCTIONS
parallel(\@tasks, \&final_cb, [$unsafe])
Executes all tasks concurrently. The final_cb is called once all tasks have invoked their done callback.
If the optional $unsafe flag is set to a true value, EV::Future will skip evaluating tasks inside a eval block and will reuse a single callback object for all tasks. This provides a massive performance boost (up to 100% faster) but bypasses per-task double-call protection and will cause issues if tasks throw exceptions. Use only when performance is critical and tasks are well-behaved.
parallel_limit(\@tasks, $limit, \&final_cb, [$unsafe])
Executes tasks concurrently, but with at most $limit tasks in-flight at any time. As each task completes, the next pending task is dispatched.
$limit is clamped to the range 1..scalar(@tasks). With $limit >= @tasks this behaves like parallel; with $limit == 1 it runs tasks sequentially.
The $unsafe flag has the same meaning as in parallel.
series(\@tasks, \&final_cb, [$unsafe])
Executes tasks one by one. The next task is only started after the current task calls its done callback.
If the optional $unsafe flag is set to a true value, error-checking overhead is bypassed for maximum performance. See parallel for warnings about exceptions.
To cancel the series and skip all subsequent tasks, pass a true value to the done callback:
series([
sub { my $d = shift; $d->(1) }, # Cancel here
sub { die "This will never run" },
], sub {
print "Series finished early\n";
});
BENCHMARKS
1000 synchronous tasks, 5000 iterations (bench/comparison.pl):
--- PARALLEL (iterations/sec) ---
EV::Future (unsafe) 4,386
EV::Future (safe) 2,262
AnyEvent cv 1,027
Future::XS 982
Promise::XS 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 3,185
EV::Future (safe) 2,591
Future::XS 893
Promise::XS 809
Safe mode allocates a per-task CV for double-call protection and wraps each dispatch in G_EVAL. Unsafe mode reuses a single shared CV and skips G_EVAL, roughly doubling throughput.
AUTHOR
vividsnow
LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.