File Coverage

blib/lib/EV/Future.pm
Criterion Covered Total %
statement 14 14 100.0
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 19 19 100.0


line stmt bran cond sub pod time code
1             package EV::Future;
2              
3 7     7   840413 use 5.010000;
  7         28  
4 7     7   42 use strict;
  7         51  
  7         198  
5 7     7   45 use warnings;
  7         14  
  7         648  
6              
7             our $VERSION = '0.04';
8              
9 7     7   1120 use EV ();
  7         5514  
  7         234  
10 7     7   44 use base 'Exporter';
  7         13  
  7         1832  
11             our @EXPORT = qw(parallel parallel_limit series);
12              
13             require XSLoader;
14             XSLoader::load('EV::Future', $VERSION);
15              
16             =head1 NAME
17              
18             EV::Future - Minimalist high-performance async control flow for EV
19              
20             =head1 SYNOPSIS
21              
22             use EV;
23             use EV::Future;
24              
25             my @w;
26             parallel([
27             sub { my $done = shift; push @w, EV::timer 0.1, 0, sub { $done->() } },
28             sub { my $done = shift; push @w, EV::timer 0.2, 0, sub { $done->() } },
29             ], sub { print "all done\n" });
30              
31             parallel_limit([
32             sub { my $done = shift; push @w, EV::timer 0.1, 0, sub { $done->() } },
33             sub { my $done = shift; push @w, EV::timer 0.2, 0, sub { $done->() } },
34             sub { my $done = shift; push @w, EV::timer 0.1, 0, sub { $done->() } },
35             ], 2, sub { print "all done (max 2 in-flight)\n" });
36              
37             series([
38             sub { my $done = shift; $done->() },
39             sub { my $done = shift; $done->() },
40             ], sub { print "all done in order\n" });
41              
42             EV::run;
43              
44             =head1 DESCRIPTION
45              
46             Three control-flow primitives (C, C, C),
47             implemented in XS for minimal overhead. All three are exported by default.
48              
49             Each task is a coderef that receives a single C callback as its only
50             argument; the task must invoke C exactly once to mark completion.
51              
52             If C<\@tasks> is empty, C fires immediately. Non-coderef elements
53             in C<\@tasks> are treated as no-op tasks that complete instantly.
54              
55             =head2 Safe vs unsafe mode
56              
57             Each function takes an optional trailing C<$unsafe> flag. In safe mode (the
58             default), each dispatch is wrapped in C, every task gets its own
59             C CV, and double-calls are silently dropped. Unsafe mode skips
60             C and reuses a single shared CV, roughly doubling throughput at the
61             cost of:
62              
63             =over 4
64              
65             =item *
66              
67             Exceptions from a task bypass cleanup and leak the internal context.
68              
69             =item *
70              
71             Double-calling C corrupts the completion counter, which may invoke
72             C before all tasks have actually finished.
73              
74             =back
75              
76             Use unsafe mode only when tasks are well-behaved and performance is
77             critical.
78              
79             =head1 FUNCTIONS
80              
81             =head2 parallel(\@tasks, \&final_cb, [$unsafe])
82              
83             Dispatch every task immediately; call C once each task has invoked
84             its C callback.
85              
86             =head2 parallel_limit(\@tasks, $limit, \&final_cb, [$unsafe])
87              
88             Dispatch tasks with at most C<$limit> in flight at any time. C<$limit> is
89             clamped to C<1..scalar(@tasks)>: C<$limit == 1> degenerates to C,
90             C<$limit E= @tasks> degenerates to C.
91              
92             There is no cancellation mechanism — all dispatched tasks must complete.
93             The truthy-C cancellation supported by C does not apply here.
94              
95             =head2 series(\@tasks, \&final_cb, [$unsafe])
96              
97             Run tasks sequentially; each task starts only after the previous calls its
98             C. To cancel the series and skip remaining tasks, pass a true value
99             to C:
100              
101             series([
102             sub { my $d = shift; $d->(1) }, # cancel here
103             sub { die "never reached" },
104             ], sub { print "finished early\n" });
105              
106             Cancellation works in both safe and unsafe modes.
107              
108             =head1 BENCHMARKS
109              
110             1000 synchronous tasks, 5000 iterations (C):
111              
112             --- PARALLEL (iterations/sec) ---
113             EV::Future (unsafe) 4,386
114             EV::Future (safe) 2,262
115             AnyEvent::cv (begin/end) 1,027
116             Future::XS::wait_all 982
117             Promise::XS::all 32
118              
119             --- PARALLEL LIMIT 10 (iterations/sec) ---
120             EV::Future (unsafe) 4,673
121             EV::Future (safe) 2,688
122             Future::Utils::fmap_void 431
123              
124             --- SERIES (iterations/sec) ---
125             EV::Future (unsafe) 5,000
126             AnyEvent::cv (stack-safe) 3,185
127             EV::Future (safe) 2,591
128             Future::XS (chain) 893
129             Promise::XS (chain) 809
130              
131             =head1 SEE ALSO
132              
133             L, L, L
134              
135             =head1 AUTHOR
136              
137             vividsnow
138              
139             =head1 LICENSE
140              
141             This library is free software; you can redistribute it and/or modify
142             it under the same terms as Perl itself.
143              
144             =cut
145              
146             1;