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 8     8   902761 use 5.010000;
  8         28  
4 8     8   48 use strict;
  8         60  
  8         288  
5 8     8   38 use warnings;
  8         18  
  8         659  
6              
7             our $VERSION = '0.05';
8              
9 8     8   1426 use EV ();
  8         6966  
  8         234  
10 8     8   46 use base 'Exporter';
  8         26  
  8         1965  
11             our @EXPORT = qw(parallel parallel_limit series race);
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             race([
43             sub { my $done = shift; push @w, EV::timer 0.1, 0, sub { $done->("a") } },
44             sub { my $done = shift; push @w, EV::timer 0.2, 0, sub { $done->("b") } },
45             ], sub { my $winner = shift; print "winner: $winner\n" });
46              
47             EV::run;
48              
49             =head1 DESCRIPTION
50              
51             Four control-flow primitives (C, C, C,
52             C), implemented in XS for minimal overhead. All four are exported by
53             default.
54              
55             Each task is a coderef that receives a single C callback as its only
56             argument; the task must invoke C exactly once to mark completion.
57              
58             If C<\@tasks> is empty, C fires immediately. Non-coderef elements
59             in C<\@tasks> are treated as no-op tasks that complete instantly.
60              
61             =head2 Safe vs unsafe mode
62              
63             Each function takes an optional trailing C<$unsafe> flag. In safe mode (the
64             default), each dispatch is wrapped in C, every task gets its own
65             C CV, and double-calls are silently dropped. Unsafe mode skips
66             C and reuses a single shared CV, roughly doubling throughput at the
67             cost of:
68              
69             =over 4
70              
71             =item *
72              
73             Exceptions from a task bypass cleanup and leak the internal context.
74              
75             =item *
76              
77             Double-calling C corrupts the completion counter, which may invoke
78             C before all tasks have actually finished.
79              
80             =back
81              
82             Use unsafe mode only when tasks are well-behaved and performance is
83             critical.
84              
85             =head1 FUNCTIONS
86              
87             =head2 parallel(\@tasks, \&final_cb, [$unsafe])
88              
89             Dispatch every task immediately; call C once each task has invoked
90             its C callback.
91              
92             =head2 parallel_limit(\@tasks, $limit, \&final_cb, [$unsafe])
93              
94             Dispatch tasks with at most C<$limit> in flight at any time. C<$limit> is
95             clamped to C<1..scalar(@tasks)>: C<$limit == 1> degenerates to C,
96             C<$limit E= @tasks> degenerates to C.
97              
98             There is no cancellation mechanism; all dispatched tasks must complete.
99             The truthy-C cancellation supported by C does not apply here.
100              
101             =head2 series(\@tasks, \&final_cb, [$unsafe])
102              
103             Run tasks sequentially; each task starts only after the previous calls its
104             C. To cancel the series and skip remaining tasks, pass a true value
105             to C:
106              
107             series([
108             sub { my $d = shift; $d->(1) }, # cancel here
109             sub { die "never reached" },
110             ], sub { print "finished early\n" });
111              
112             Cancellation works in both safe and unsafe modes.
113              
114             =head2 race(\@tasks, \&final_cb, [$unsafe])
115              
116             Dispatch every task; call C with the arguments passed to the
117             first C invocation. Subsequent C calls (whether from the
118             winning task or losers) are silently ignored.
119              
120             Losing tasks continue to run; C does not cancel their EV
121             watchers (it didn't create them). To tear losers down, hold their
122             watchers in a shared lvalue and clear it from C:
123              
124             my @w;
125             race([
126             sub { my $d = shift; push @w, EV::timer 0.1, 0, sub { $d->("a") } },
127             sub { my $d = shift; push @w, EV::timer 0.2, 0, sub { $d->("b") } },
128             ], sub { my $winner = shift; @w = () });
129              
130             Non-coderef elements in C<\@tasks> count as instantly-completed winners
131             (with no arguments) and short-circuit dispatch.
132              
133             =head1 BENCHMARKS
134              
135             1000 synchronous tasks, 5000 iterations (C):
136              
137             --- PARALLEL (iterations/sec) ---
138             EV::Future (unsafe) 4,386
139             EV::Future (safe) 2,262
140             AnyEvent::cv (begin/end) 1,027
141             Future::XS::wait_all 982
142             Promise::XS::all 32
143              
144             --- PARALLEL LIMIT 10 (iterations/sec) ---
145             EV::Future (unsafe) 4,673
146             EV::Future (safe) 2,688
147             Future::Utils::fmap_void 431
148              
149             --- SERIES (iterations/sec) ---
150             EV::Future (unsafe) 5,000
151             AnyEvent::cv (stack-safe) 3,185
152             EV::Future (safe) 2,591
153             Future::XS (chain) 893
154             Promise::XS (chain) 809
155              
156             =head1 SEE ALSO
157              
158             L, L, L
159              
160             =head1 AUTHOR
161              
162             vividsnow
163              
164             =head1 LICENSE
165              
166             This library is free software; you can redistribute it and/or modify
167             it under the same terms as Perl itself.
168              
169             =cut
170              
171             1;