forked from stevan/promises-perl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
EV.pm
105 lines (74 loc) · 2.54 KB
/
EV.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package Promises::Deferred::EV;
# ABSTRACT: An implementation of Promises in Perl
use strict;
use warnings;
use EV;
use parent 'Promises::Deferred';
# Before the pipe-based approach used below, there was an EV::timer-based
# approach for _notify_backend. The current code is much more performant:
# Original code (on a laptop on battery power):
# Backend: Promises::Deferred::EV
# Benchmark: running one, two for at least 10 CPU seconds...
# Benchmark: running one, two for at least 10 CPU seconds...
# one: 67 wallclock secs @ 1755.16/s (n=17692)
# two: 53 wallclock secs @ 770.03/s (n=7785)
# New approach:
# Backend: Promises::Deferred::EV
# Benchmark: running one, two for at least 10 CPU seconds...
# one: 10 wallclock secs @ 10949.19/s (n=115076)
# two: 10 wallclock secs @ 3964.58/s (n=41747)
my ($socket_pid, $socket_send, $socket_recv, $socket_io,
$read_buf, @io_callbacks);
sub _do_callbacks {
my @cbs = @io_callbacks;
@io_callbacks = ();
sysread $socket_recv, $read_buf, 16;
for my $cb (@cbs) {
$cb->();
}
}
sub _notify_backend {
my ( $self, $callbacks, $result ) = @_;
if (! $socket_pid || $socket_pid != $$) {
$socket_pid = $$;
close($socket_send) if defined $socket_send;
close($socket_recv) if defined $socket_recv;
pipe($socket_recv, $socket_send);
$socket_io = EV::io($socket_recv, EV::READ, \&_do_callbacks);
}
push @io_callbacks, @$callbacks;
syswrite $socket_send, ' ';
}
# sub _notify_backend {
# my ( $self, $callbacks, $result ) = @_;
# my $w; $w = EV::timer( 0, 0, sub {
# foreach my $cb (@$callbacks) {
# $cb->(@$result);
# }
# undef $w;
# });
# }
sub _timeout {
my ( $self, $timeout, $callback ) = @_;
my $id = EV::timer $timeout, 0, $callback;
return sub { undef $id };
}
1;
__END__
=head1 SYNOPSIS
use Promises backend => ['EV'], qw[ deferred collect ];
# ... everything else is the same
=head1 DESCRIPTION
The "Promise/A+" spec strongly suggests that the callbacks
given to C<then> should be run asynchronously (meaning in the
next turn of the event loop), this module provides support for
doing so using the L<EV> module.
Module authors should not care which event loop will be used but
instead should just the Promises module directly:
package MyClass;
use Promises qw(deferred collect);
End users of the module can specify which backend to use at the start of
the application:
use Promises -backend => ['EV'];
use MyClass;
=cut