AnyEvent-Fork

 view release on metacpan or  search on metacpan

Fork.pm  view on Meta::CPAN


   # create a pool template, initialise it and give it the socket
   my $pool = AnyEvent::Fork
                 ->new
                 ->require ("Some::Stuff", "My::Server")
                 ->send_fh ($listener);

   # now create 10 identical workers
   for my $id (1..10) {
      $pool
         ->fork
         ->send_arg ($id)
         ->run ("My::Server::run");
   }

   # now do other things - maybe use the filehandle provided by run
   # to wait for the processes to die. or whatever.

C<My::Server> might look like this:

   package My::Server;

   sub run {
      my ($slave, $listener, $id) = @_;

      close $slave; # we do not use the socket, so close it to save resources

      # we could go ballistic and use e.g. AnyEvent here, or IO::AIO,
      # or anything we usually couldn't do in a process forked normally.
      while (my $socket = $listener->accept) {
         # do sth. with new socket
      }
   }

=head2 use AnyEvent::Fork as a faster fork+exec

This runs C</bin/echo hi>, with standard output redirected to F</tmp/log>
and standard error redirected to the communications socket. It is usually
faster than fork+exec, but still lets you prepare the environment.

   open my $output, ">/tmp/log" or die "$!";

   AnyEvent::Fork
      ->new
      ->eval ('
           # compile a helper function for later use
           sub run {
              my ($fh, $output, @cmd) = @_;

              # perl will clear close-on-exec on STDOUT/STDERR
              open STDOUT, ">&", $output or die;
              open STDERR, ">&", $fh or die;

              exec @cmd;
           }
        ')
      ->send_fh ($output)
      ->send_arg ("/bin/echo", "hi")
      ->run ("run", my $cv = AE::cv);

   my $stderr = $cv->recv;

=head2 For stingy users: put the worker code into a C<DATA> section.

When you want to be stingy with files, you can put your code into the
C<DATA> section of your module (or program):

   use AnyEvent::Fork;

   AnyEvent::Fork
      ->new
      ->eval (do { local $/; <DATA> })
      ->run ("doit", sub { ... });

   __DATA__

   sub doit {
      ... do something!
   }

=head2 For stingy standalone programs: do not rely on external files at
all.

For single-file scripts it can be inconvenient to rely on external
files - even when using a C<DATA> section, you still need to C<exec> an
external perl interpreter, which might not be available when using
L<App::Staticperl>, L<Urlader> or L<PAR::Packer> for example.

Two modules help here - L<AnyEvent::Fork::Early> forks a template process
for all further calls to C<new_exec>, and L<AnyEvent::Fork::Template>
forks the main program as a template process.

Here is how your main program should look like:

   #! perl

   # optional, as the very first thing.
   # in case modules want to create their own processes.
   use AnyEvent::Fork::Early;

   # next, load all modules you need in your template process
   use Example::My::Module
   use Example::Whatever;

   # next, put your run function definition and anything else you
   # need, but do not use code outside of BEGIN blocks.
   sub worker_run {
      my ($fh, @args) = @_;
      ...
   }

   # now preserve everything so far as AnyEvent::Fork object
   # in $TEMPLATE.
   use AnyEvent::Fork::Template;

   # do not put code outside of BEGIN blocks until here

   # now use the $TEMPLATE process in any way you like

   # for example: create 10 worker processes
   my @worker;

Fork.pm  view on Meta::CPAN

      }

      $PERL = $perl;
   }

   require Proc::FastSpawn;

   my ($fh, $slave) = AnyEvent::Util::portable_socketpair;
   Proc::FastSpawn::fd_inherit (fileno $slave);

   # new fh's should always be set cloexec (due to $^F),
   # but hey, not on win32, so we always clear the inherit flag.
   Proc::FastSpawn::fd_inherit (fileno $fh, 0);

   # quick. also doesn't work in win32. of course. what did you expect
   #local $ENV{PERL5LIB} = join ":", grep !ref, @INC;
   my %env = %ENV;
   $env{PERL5LIB} = join +($^O eq "MSWin32" ? ";" : ":"), grep !ref, @INC;

   my $pid = Proc::FastSpawn::spawn (
      $PERL,
      [$PERL, "-MAnyEvent::Fork::Serve", "-e", "AnyEvent::Fork::Serve::me", fileno $slave, $$],
      [map "$_=$env{$_}", keys %env],
   ) or die "unable to spawn AnyEvent::Fork server: $!";

   $self->_new ($fh, $pid)
}

=item $pid = $proc->pid

Returns the process id of the process I<iff it is a direct child of the
process running AnyEvent::Fork>, and C<undef> otherwise. As a general
rule (that you cannot rely upon), processes created via C<new_exec>,
L<AnyEvent::Fork::Early> or L<AnyEvent::Fork::Template> are direct
children, while all other processes are not.

Or in other words, you do not normally have to take care of zombies for
processes created via C<new>, but when in doubt, or zombies are a problem,
you need to check whether a process is a diretc child by calling this
method, and possibly creating a child watcher or reap it manually.

=cut

sub pid {
   $_[0][PID]
}

=item $proc = $proc->eval ($perlcode, @args)

Evaluates the given C<$perlcode> as ... Perl code, while setting C<@_>
to the strings specified by C<@args>, in the "main" package (so you can
access the args using C<$_[0]> and so on, but not using implicit C<shit>
as the latter works on C<@ARGV>).

This call is meant to do any custom initialisation that might be required
(for example, the C<require> method uses it). It's not supposed to be used
to completely take over the process, use C<run> for that.

The code will usually be executed after this call returns, and there is no
way to pass anything back to the calling process. Any evaluation errors
will be reported to stderr and cause the process to exit.

If you want to execute some code (that isn't in a module) to take over the
process, you should compile a function via C<eval> first, and then call
it via C<run>. This also gives you access to any arguments passed via the
C<send_xxx> methods, such as file handles. See the L<use AnyEvent::Fork as
a faster fork+exec> example to see it in action.

Returns the process object for easy chaining of method calls.

It's common to want to call an iniitalisation function with some
arguments. Make sure you actually pass C<@_> to that function (for example
by using C<&name> syntax), and do not just specify a function name:

   $proc->eval ('&MyModule::init', $string1, $string2);

=cut

sub eval {
   my ($self, $code, @args) = @_;

   $self->_cmd (e => pack "(w/a*)*", $code, @args);

   $self
}

=item $proc = $proc->require ($module, ...)

Tries to load the given module(s) into the process

Returns the process object for easy chaining of method calls.

=cut

sub require {
   my ($self, @modules) = @_;

   s%::%/%g for @modules;
   $self->eval ('require "$_.pm" for @_', @modules);

   $self
}

=item $proc = $proc->send_fh ($handle, ...)

Send one or more file handles (I<not> file descriptors) to the process,
to prepare a call to C<run>.

The process object keeps a reference to the handles until they have
been passed over to the process, so you must not explicitly close the
handles. This is most easily accomplished by simply not storing the file
handles anywhere after passing them to this method - when AnyEvent::Fork
is finished using them, perl will automatically close them.

Returns the process object for easy chaining of method calls.

Example: pass a file handle to a process, and release it without
closing. It will be closed automatically when it is no longer used.

   $proc->send_fh ($my_fh);
   undef $my_fh; # free the reference if you want, but DO NOT CLOSE IT



( run in 0.677 second using v1.01-cache-2.11-cpan-85f18b9d64f )