File Coverage

blib/lib/Promises/Deferred/AnyEvent.pm
Criterion Covered Total %
statement 28 32 87.5
branch 5 8 62.5
condition 2 3 66.6
subroutine 6 8 75.0
pod n/a
total 41 51 80.3


line stmt bran cond sub pod time code
1             package Promises::Deferred::AnyEvent;
2             our $AUTHORITY = 'cpan:YANICK';
3             # ABSTRACT: An implementation of Promises in Perl
4             $Promises::Deferred::AnyEvent::VERSION = '1.05';
5 2     2   1243 use strict;
  2         4  
  2         93  
6 2     2   11 use warnings;
  2         3  
  2         158  
7              
8 2     2   57 use AnyEvent;
  2         5  
  2         62  
9              
10 2     2   9 use parent 'Promises::Deferred';
  2         3  
  2         19  
11              
12             # Before the pipe-based approach used below, there was an
13             # AnyEvent->postpone-based approach for _notify_backend.
14             # The current code is much more performant:
15              
16             # Original code (on a laptop on battery power):
17             # Backend: Promises::Deferred::AnyEvent
18             # Benchmark: running one, two for at least 10 CPU seconds...
19             # one: 47 wallclock secs @ 2754.62/s (n=32780)
20             # two: 37 wallclock secs @ 2450.45/s (n=24676)
21              
22             # New approach:
23             # Backend: Promises::Deferred::AnyEvent
24             # Benchmark: running one, two for at least 10 CPU seconds...
25             # one: 10 wallclock secs @ 10182.12/s (n=106505)
26             # two: 10 wallclock secs @ 3847.01/s (n=39855)
27              
28              
29             my ($socket_pid, $socket_send, $socket_recv, $socket_io,
30             $read_buf, @io_callbacks);
31              
32             sub _do_callbacks {
33 8     8   1816 my @cbs = @io_callbacks;
34 8         25 @io_callbacks = ();
35 8         39 sysread $socket_recv, $read_buf, 16;
36 8         17 for my $cb_grp (@cbs) {
37 8         14 my ($result, $cbs) = @$cb_grp;
38 8         11 my @r = @$result;
39 8         55 $_->(@r) for @$cbs;
40             }
41             }
42              
43             sub _notify_backend {
44 8 100 66 8   44 if (! $socket_pid || $socket_pid != $$) {
45 2         31 $socket_pid = $$;
46 2 50       8 close($socket_send) if defined $socket_send;
47 2 50       7 close($socket_recv) if defined $socket_recv;
48 2         108 pipe($socket_recv, $socket_send);
49 2         23 $socket_io = AnyEvent->io(
50             fh => $socket_recv,
51             poll => 'r',
52             cb => \&_do_callbacks);
53             }
54              
55             # skip signalling when there are callbacks already waiting
56 8 50       5954 if (not @io_callbacks) {
57 8         78 syswrite $socket_send, ' ';
58             }
59 8         24 push @io_callbacks, [ $_[2], $_[1] ];
60             }
61              
62             sub _timeout {
63 0     0     my ( $self, $timeout, $callback ) = @_;
64              
65 0           my $id = AnyEvent->timer( after => $timeout, cb => $callback );
66            
67 0     0     return sub { undef $id };
  0            
68             }
69              
70             1;
71              
72             __END__