EV-Future

 view release on metacpan or  search on metacpan

README.md  view on Meta::CPAN

## Install

```bash
perl Makefile.PL && make && make test
```

Requires Perl 5.14+, EV 4.37+, and a C compiler.

## Benchmarks

1000 sync tasks x 5000 iterations (`bench/comparison.pl`; `race` is not covered by
that script, so it has no row here). Measured with EV 4.37, AnyEvent 7.17,
Future::XS 0.15, Promise::XS 0.21 and Future::Utils 0.52:

| | parallel | parallel_limit(10) | series |
|---|---:|---:|---:|
| EV::Future (unsafe) | 9,259 | 7,692 | 7,692 |
| EV::Future (safe) | 4,098 | 4,032 | 3,968 |
| AnyEvent cv | 1,563 | - | 4,717 |
| Future::XS | 1,563 | 624 | 1,241 |
| Promise::XS | 1,323 | - | 1,157 |

bench/benchmark.pl  view on Meta::CPAN

    print "Running $name...\n";
    my $start = time;
    for (1..$ITERATIONS) {
        $code->();
    }
    my $end = time;
    my $elapsed = $end - $start;
    printf "%-30s: %8.4fs (%10.2f/s)\n", $name, $elapsed, $ITERATIONS / $elapsed;
}

print "Benchmarking $COUNT synchronous tasks over $ITERATIONS iterations:\n";

run_bench('EV::Future::parallel', sub {
    EV::Future::parallel(\@tasks, sub { });
});

run_bench('EV::Future::parallel (unsafe)', sub {
    EV::Future::parallel(\@tasks, sub { }, 1);
});

run_bench('EV::Future::parallel_limit(10)', sub {

bench/comparison.pl  view on Meta::CPAN

}

sub bench_future_fmap_void {
    my @items = 1..$COUNT;
    my $f = fmap_void {
        return Future->done;
    } foreach => \@items, concurrent => 10;
    $f->get;
}

print "Benchmarking $COUNT tasks ($ITERATIONS iterations):\n";

print "\n--- PARALLEL ---\n";
timethese($ITERATIONS, {
    'EV::Future::parallel'          => \&bench_ev_future_parallel,
    'EV::Future::parallel (unsafe)' => \&bench_ev_future_parallel_unsafe,
    'Promise::XS::all'              => \&bench_promise_xs_parallel,
    'Future::XS::wait_all'          => \&bench_future_xs_parallel,
    'AnyEvent::cv (begin/end)'      => \&bench_anyevent_parallel,
});

lib/EV/Future.pm  view on Meta::CPAN

unsafe-mode exception, whose counters freeze instead; see
L</"Safe vs unsafe mode">.

In unsafe mode, double-calling C<done> corrupts the completion counter, so
C<pending> under-reports for C<parallel> and C<parallel_limit> for the same
reason C<final_cb> can fire early. The same double-call can drive the in-flight
count below zero; C<active> is floored at 0 rather than reporting a negative.

=head1 BENCHMARKS

1000 synchronous tasks, 5000 iterations (C<bench/comparison.pl>). The script
covers the task form only, so C<race> and the three map primitives have no
figures here; see L</"Task form versus map form"> below for those. Measured
with EV 4.37, AnyEvent 7.17, Future::XS 0.15, Promise::XS 0.21 and
Future::Utils 0.52.

  --- PARALLEL (iterations/sec) ---
  EV::Future (unsafe)          9,259
  EV::Future (safe)            4,098
  AnyEvent::cv (begin/end)     1,563
  Future::XS::wait_all         1,563
  Promise::XS::all             1,323

  --- PARALLEL LIMIT 10 (iterations/sec) ---
  EV::Future (unsafe)          7,692
  EV::Future (safe)            4,032
  Future::Utils::fmap_void       624

  --- SERIES (iterations/sec) ---
  EV::Future (unsafe)          7,692
  AnyEvent::cv (stack-safe)    4,717
  EV::Future (safe)            3,968
  Future::XS (chain)           1,241
  Promise::XS (chain)          1,157

=head2 Task form versus map form

C<bench/map_vs_task.pl>, 100 elements, unsafe mode, as cachegrind instruction
counts per call, which are deterministic where wall-clock timings on a loaded



( run in 0.921 second using v1.01-cache-2.11-cpan-4ab04211f4c )