AnyEvent-Fork-RPC
view release on metacpan or search on metacpan
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 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:
If "async" was false when $rpc was created (the default), then, if
you call $rpc, the $function is invoked with all arguments passed to
$rpc except the last one (the callback). When the function returns,
the callback will be invoked with all the return values.
If "async" was true, then the $function receives an additional
initial argument, the result callback. In this case, returning from
$function does nothing - the function only counts as "done" when the
result callback is called, and any arguments passed to it are
considered the return values. This makes it possible to "return"
from event handlers or e.g. Coro threads.
The other thing that can be done with the RPC object is to destroy
it. In this case, the child process will execute all remaining RPC
calls, report their results, and then exit.
See the examples section earlier in this document for some actual
examples.
CHILD PROCESS USAGE
The following function is not available in this module. They are only
generates them and the parent process is slow accepting them.
The API is not a straightforward RPC pattern - you have to call a
"done" callback to pass return values and signal completion. Also,
more importantly, the API starts jobs as fast as possible - when
1000 jobs are queued and the jobs are slow, they will all run
concurrently. The child must implement some queueing/limiting
mechanism if this causes problems. Alternatively, the parent could
limit the amount of rpc calls that are outstanding.
Blocking use of condvars is not supported (in the main thread,
outside of e.g. Coro threads).
Using event-based modules such as IO::AIO, Gtk2, Tk and so on is
easy.
Passing file descriptors
Unlike AnyEvent::Fork, this module has no in-built file handle or file
descriptor passing abilities.
The reason is that passing file descriptors is extraordinary tricky
business, and conflicts with efficient batching of messages.
And unless your system is I<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 L<AnyEvent::Fork> does not
actually fork, you are free to use about any module in the child, not just
L<AnyEvent>, but also L<IO::AIO>, or L<Tk> for example.
=head2 Example 3: Asynchronous backend with Coro
With L<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 run {
my ($done, $func, @arg) = @_;
Coro::async_pool {
$done->($func->(@arg));
};
}
The C<run> function creates a new thread for every invocation, using the
first argument as function name, and calls the C<$done> callback on it's
return values. This makes it quite natural to define the C<add> and C<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:
If C<async> was false when C<$rpc> was created (the default), then, if you
call C<$rpc>, the C<$function> is invoked with all arguments passed to
C<$rpc> except the last one (the callback). When the function returns, the
callback will be invoked with all the return values.
If C<async> was true, then the C<$function> receives an additional
initial argument, the result callback. In this case, returning from
C<$function> does nothing - the function only counts as "done" when the
result callback is called, and any arguments passed to it are considered
the return values. This makes it possible to "return" from event handlers
or e.g. Coro threads.
The other thing that can be done with the RPC object is to destroy it. In
this case, the child process will execute all remaining RPC calls, report
their results, and then exit.
See the examples section earlier in this document for some actual
examples.
=back
parent process is slow accepting them.
The API is not a straightforward RPC pattern - you have to call a
"done" callback to pass return values and signal completion. Also, more
importantly, the API starts jobs as fast as possible - when 1000 jobs
are queued and the jobs are slow, they will all run concurrently. The
child must implement some queueing/limiting mechanism if this causes
problems. Alternatively, the parent could limit the amount of rpc calls
that are outstanding.
Blocking use of condvars is not supported (in the main thread, outside of
e.g. L<Coro> threads).
Using event-based modules such as L<IO::AIO>, L<Gtk2>, L<Tk> and so on is
easy.
=back
=head2 Passing file descriptors
Unlike L<AnyEvent::Fork>, this module has no in-built file handle or file
descriptor passing abilities.
( run in 0.530 second using v1.01-cache-2.11-cpan-3cd7ad12f66 )