AnyEvent-Fork-RPC
view release on metacpan or search on metacpan
count 2 of 2
job 2 finished
count 2 of 3
count 3 of 3
job 3 finished
While the overall ordering isn't guaranteed, the async backend still
guarantees that events and responses are delivered to the parent process
in the exact same ordering as they were generated in the child process.
And unless your system is *very* busy, it should clearly show that the
job started last will finish first, as it has the lowest count.
This concludes the async example. Since AnyEvent::Fork does not actually
fork, you are free to use about any module in the child, not just
AnyEvent, but also IO::AIO, or Tk for example.
Example 3: Asynchronous backend with Coro
With Coro you can create a nice asynchronous backend implementation by
defining an rpc server function that creates a new Coro thread for every
request that calls a function "normally", i.e. the parameters from the
parent process are passed to it, and any return values are returned to
the parent process, e.g.:
package My::Arith;
sub add {
return $_[0] + $_[1];
}
sub mul {
return $_[0] * $_[1];
}
sub run {
my ($done, $func, @arg) = @_;
Coro::async_pool {
$done->($func->(@arg));
};
}
The "run" function creates a new thread for every invocation, using the
first argument as function name, and calls the $done callback on it's
return values. This makes it quite natural to define the "add" and "mul"
functions to add or multiply two numbers and return the result.
Since this is the asynchronous backend, it's quite possible to define
RPC function that do I/O or wait for external events - their execution
will overlap as needed.
The above could be used like this:
my $rpc = AnyEvent::Fork
->new
->require ("MyWorker")
->AnyEvent::Fork::RPC::run ("My::Arith::run",
on_error => ..., on_event => ..., on_destroy => ...,
);
$rpc->(add => 1, 3, Coro::rouse_cb); say Coro::rouse_wait;
$rpc->(mul => 3, 2, Coro::rouse_cb); say Coro::rouse_wait;
The "say"'s will print 4 and 6.
Example 4: Forward AnyEvent::Log messages using "on_event"
This partial example shows how to use the "event" function to forward
AnyEvent::Log messages to the parent.
For this, the parent needs to provide a suitable "on_event":
->AnyEvent::Fork::RPC::run (
on_event => sub {
if ($_[0] eq "ae_log") {
my (undef, $level, $message) = @_;
AE::log $level, $message;
} else {
# other event types
}
},
)
In the child, as early as possible, the following code should
reconfigure AnyEvent::Log to log via "AnyEvent::Fork::RPC::event":
$AnyEvent::Log::LOG->log_cb (sub {
my ($timestamp, $orig_ctx, $level, $message) = @{+shift};
if (defined &AnyEvent::Fork::RPC::event) {
AnyEvent::Fork::RPC::event (ae_log => $level, $message);
} else {
warn "[$$ before init] $message\n";
}
});
There is an important twist - the "AnyEvent::Fork::RPC::event" function
is only defined when the child is fully initialised. If you redirect the
log messages in your "init" function for example, then the "event"
function might not yet be available. This is why the log callback checks
whether the function is there using "defined", and only then uses it to
log the message.
PARENT PROCESS USAGE
This module exports nothing, and only implements a single function:
my $rpc = AnyEvent::Fork::RPC::run $fork, $function, [key => value...]
The traditional way to call it. But it is way cooler to call it in
the following way:
my $rpc = $fork->AnyEvent::Fork::RPC::run ($function, [key => value...])
This "run" function/method can be used in place of the
AnyEvent::Fork::run method. Just like that method, it takes over the
AnyEvent::Fork process, but instead of calling the specified
$function directly, it runs a server that accepts RPC calls and
handles responses.
It returns a function reference that can be used to call the
function in the child process, handling serialisation and data
transfers.
The following key/value pairs are allowed. It is recommended to have
at least an "on_error" or "on_event" handler set.
( run in 0.424 second using v1.01-cache-2.11-cpan-483215c6ad5 )