GRID-Machine

 view release on metacpan or  search on metacpan

lib/GRID/Machine.pod  view on Meta::CPAN

When executed, the former code produces the following output:

    $ struct.pl
    $VAR1 = bless( {
                     'stderr' => '',
                     'errmsg' => '',
                     'type' => 'RETURNED',
                     'stdout' => '',
                     'errcode' => 0,
                     'results' => [
                                    [ 'Smith', 'Garcia' ]
                                  ]
                   }, 'GRID::Machine::Result' );

A C<GRID::Machine::Result> result object describes the result of a RPC.
The C<results> attribute is an ARRAY reference holding the result returned
by the call. The other attributes C<stdout>, C<stderr>, etc. hold
the respective outputs. 
See section L<THE GRID::Machine::Result CLASS> for a more detailed description
of C<GRID::Machine::Result> objects.

=head3 The Algorithm of C<eval>

When a call

            $result = $machine->eval( $code, @args )

occurs, the code C<$code> should be passed in a string, and is compiled using a string
C<eval> in the remote host:

               my $subref = eval "use strict; sub { $code }";

Files C<STDOUT> and C<STDERR> are redirected and the subroutine
referenced by C<$subref> is called 
inside an eval with the specified arguments:

                my @results = eval { $subref->( @_ ) };

=head3 Errors and Exceptions

If there are errors at compile time, they will be
collected into the  C<GRID::Machine::Result> object. 
In the following example the code to eval has an error (variable
C<$q> is not declared):


  ~/grid-machine/examples$ cat -n syntaxerr2.pl 
     1  #!/usr/local/bin/perl -w
     2  use strict;
     3  use GRID::Machine;
     4  use Data::Dumper;
     5  
     6  my $machine = GRID::Machine->new(host => 'user@machine.domain.es');
     7  
     8  my $p = { name => 'Peter', familyname => [ 'Smith', 'Garcia'] };
     9  
    10  my $r = $machine->eval( q{ $q = shift; $q->{familyname} }, $p);
    11  
    12  die  Dumper($r) unless $r->ok;
    13  
    14  print "Still alive\n";


When executed this code produces something like:

  $VAR1 = bless( {
                 'stderr' => '',
                 'errmsg' => 'user@machine.domain.es: Error while compiling eval \'$q = shift; $q->{fam...\'
                  Global symbol "$q" requires explicit package name at syntaxerr2.pl line 10, <STDIN> line 230.
                  Global symbol "$q" requires explicit package name at syntaxerr2.pl line 10, <STDIN> line 230.',
                 'type' => 'DIED',
                 'stdout' => '',
                 'errcode' => 0
               }, 'GRID::Machine::Result' );

The error message accurately reports the correct source offending line.

C<GRID::Machine::Result> objects have an C<ok> method which
returns TRUE if the RPC call didn't died. Therefore a common idiom
after a RPC is:

                          die "$r" unless $r->ok;

=head3 Scope and Visibility Issues

Since the C<eval> method wraps the code into a subroutine 
(see section L<The Algorithm of eval>) like this

               my $subref = eval "use strict; sub { $code }";

variables declared using C<our> inside an C<eval> must be redeclared
in subsequent C<evals> to make them visible. The following code produces an error message:

 $ cat -n vars1.pl
     1  #!/usr/local/bin/perl -w
     2  use strict;
     3  use GRID::Machine qw(qc);
     4
     5  my $machine = GRID::Machine->new(host => 'user@remote');
     6
     7  $machine->eval(q{
     8    our $h;
     9    $h = [4..9];
    10  });
    11
    12  my $r = $machine->eval(qc q{
    13    $h = [map {$_*$_} @$h];
    14  });
    15
    16  die $r unless $r->noerr;


The interpreter complains about C<$h>:

  $ vars1.pl
  user@remote: Error while compiling eval. \
    Global symbol "$h" requires explicit package name at ./vars1.pl line 13,\
                                                           <STDIN> line 198.
    Global symbol "$h" requires explicit package name at ./vars1.pl line 13, \
                                                           <STDIN> line 198.

lib/GRID/Machine.pod  view on Meta::CPAN

     3  use GRID::Machine;
     4
     5  my $machine = shift || 'orion.pcg.ull.es';
     6  my $m = GRID::Machine->new( host => $machine );
     7
     8  my $WTR = IO::Handle->new();
     9  my $RDR = IO::Handle->new();
    10  my $ERR = IO::Handle->new();
    11  my $pid = $m->open3($WTR, $RDR, $ERR, 'bc');
    12
    13  my $line;
    14
    15  print $WTR "3*2\n";
    16  $line = <$RDR>;
    17  print STDOUT "3*2 = $line";
    18
    19  print $WTR "3/(2-2)\n";
    20  $line = <$ERR>;
    21  print STDOUT "3/(2-2) produces error = $line\n";
    22
    23  print $WTR "quit\n";
    24  wait;

When executed, the former program produces an output like this:

  $ open3bc.pl
  3*2 = 6
  3/(2-2) produces error = Runtime error (func=(main), adr=11): Divide by zero



=head1 REMOTE PROCESSES (FORKING)


=head2 The C<fork> method

The C<fork> method of C<GRID::Machine> objects can be used to fork a process in the remote machine,
as shown in the following example:

  $ cat -n fork5.pl 
     1  #!/usr/bin/perl -w
     2  use strict;
     3  use GRID::Machine;
     4  use Data::Dumper;
     5  
     6  my $host = $ENV{GRID_REMOTE_MACHINE};
     7  my $machine = GRID::Machine->new( host => $host );
     8  
     9  my $p = $machine->fork( q{
    10  
    11     print "stdout: Hello from process $$. args = (@_)\n";
    12     print STDERR "stderr: Hello from process $$\n";
    13  
    14     use List::Util qw{sum};
    15     return { s => sum(@_), args => [ @_ ] };
    16   },
    17   args => [ 1..4 ],
    18  );
    19  
    20  # GRID::Machine::Process objects are overloaded
    21  print "Doing something while $p is still alive  ...\n" if $p; 
    22  
    23  my $r = $machine->waitpid($p);
    24  
    25  print "Result from process '$p': ",Dumper($r),"\n";
    26  print "GRID::Machine::Process::Result objects are overloaded in a string context:\n$r\n";


When executed, the former program produces an output similar to this:

  $ perl fork5.pl 
  Doing something while 5220:5230:some.machine:5234:5237 is still alive  ...
  Result from process '5220:5230:some.machine:5234:5237': $VAR1 = bless( {
                   'machineID' => 0,
                   'stderr' => 'stderr: Hello from process 5237
  ',
                   'descriptor' => 'some.machine:5234:5237',
                   'status' => 0,
                   'waitpid' => 5237,
                   'errmsg' => '',
                   'stdout' => 'stdout: Hello from process 5237. args = (1 2 3 4)
  ',
                   'results' => [ { 'args' => [ 1, 2, 3, 4 ], 's' => 10 } ]
                 }, 'GRID::Machine::Process::Result' );

  GRID::Machine::Process::Result objects are overloaded in a string context:
  stdout: Hello from process 5237. args = (1 2 3 4)
  stderr: Hello from process 5237


The C<fork> method returns a L<GRID::Machine::Process> object. The first argument must be a string containing
the code that will be executed by the forked process in the remote machine.
Such code is always called in a list context.
The C<fork> method admits the following arguments:

=over 2

=item * C<stdin>

The name of the file to which C<stdin> will be redirected

=item * C<stdout>

The name of the file to which C<stdout> will be redirected. If not specified a temporary file will be used

=item * C<stderr>

The name of the file to which C<stderr> will be redirected. If not specified a temporary file will be used

=item * C<result>

The name of the file to which the result computed by the child process  will be dumped. If not specified a temporary file will be used

=item * C<args>

The arguments for the code executed by the remote child process

=back

=head2 C<GRID::Machine::Process> objects

L<GRID::Machine::Process> objects have been overloaded. In a string context 
a L<GRID::Machine::Process> object 
produces the concatenation C<hostname:clientPID:remotePID>. 
In a boolean context it returns true if the process is alive and false otherwise.
This way, the execution of line 21 in the program above:

    21  print "Doing something while $p is still alive  ...\n" if $p; 

produces an output like:

  Doing something while 5220:5230:some.machine:5234:5237 is still alive  ...

if the remote process is still alive. The descriptor of the process
C<5220:5230:some.machine:5234:5237>
is a colon separated sequence of five components:

=over 2

=item 1 - The PID of the local process executing L<GRID::Machine> 

=item 2 - The PID of the local process in charge of the connection with the remote 
machine

=item 3 - The name of the remote machine 

=item 4 - The PID of the remote process executing L<GRID::Machine::REMOTE>

=item 5 - The PID of the child process created by C<fork>

=back

When evaluated in a boolean context, a L<GRID::Machine::Process> returns
1 if it is alive and 0 otherwise.

=head2 The C<waitpid> method

The C<waitpid> method  waits for the L<GRID::Machine::Process> received as first argument 
to terminate. Additional C<FLAGS> as in perl C<waitpid> can be passed as arguments.
It returns a L<GRID::Machine::Process::Result> object, whose attributes contain:


=over 2 

=item * C<stdout>  

A string containing the output to C<STDOUT> of the remote child process

=item * C<stderr>

A string containing the output to C<STDERR> of the remote child process

=item * C<results>

The list of values returned by the child process. The forking code 
is always called in a list context.

=item * C<status>

The value associated with C<$?> as returned by the remote child process.

=item * C<waitpid>

The value returned by the Perl C<waitpid> function when synchronized 
with the remote child process.
It is usually the value is either the C<pid> of the deceased process, or C<-1> 
if there was no such child process.  On some systems, a value of C<0> indicates that
there are processes still running.  

=item * C<errmsg> 

The child error as in C<$@> 

=item * C<machineID>

The logical identifier of the associated L<GRID::Machine>.
By default, 0 if it was the first L<GRID::Machine> created, 1 if it was the second, etc.

=back 

=head2  The C<waitall> method

It is similar to C<waitpid> but instead waits for any child process.

Behaves like the wait(2) system call on your system: it waits
for a child process to terminate and returns 

=over 2

=item * The C<GRID::Machine::Process::Result>
object associated with the  deceased process if it was called via the L<GRID::Machine> 
C<fork> method, or 

=item * The PID of the deceased process if there is no C<GRID::Machine::Process>
associated (it was called using an ordinary C<fork>)

=item * C<-1> if there are no child processes.  
Note that a return value of C<-1> could mean that child processes are
being automatically reaped, as described in perlipc.

=back

See an example:

  $ cat -n wait1.pl 
     1  #!/usr/bin/perl -w
     2  use strict;
     3  use GRID::Machine;
     4  use Data::Dumper;
     5  
     6  my $host = $ENV{GRID_REMOTE_MACHINE};
     7  my $machine = GRID::Machine->new( host => $host );
     8  
     9  my $p = $machine->fork( q{
    10  
    11     print "stdout: Hello from process $$. args = (@_)\n";
    12     print STDERR "stderr: Hello from process $$\n";
    13  
    14     use List::Util qw{sum};
    15     return { s => sum(@_), args => [ @_ ] };
    16   },
    17   args => [ 1..4 ],
    18  );
    19  
    20  # GRID::Machine::Process objects are overloaded
    21  print "Doing something while $p is still alive  ...\n" if $p; 
    22  
    23  my $r = $machine->waitall();
    24  
    25  print "Result from process '$p': ",Dumper($r),"\n";
    26  print "GRID::Machine::Process::Result objects are overloaded in a string context:\n$r\n";

When executed produces:

  $ perl wait1.pl 
  Doing something while 1271:1280:local:1284:1287 is still alive  ...
  Result from process '1271:1280:local:1284:1287': $VAR1 = bless( {
                   'machineID' => 0,
                   'stderr' => 'stderr: Hello from process 1287
  ',
                   'descriptor' => 'local:1284:1287',
                   'status' => 0,
                   'waitpid' => 1287,
                   'errmsg' => '',
                   'stdout' => 'stdout: Hello from process 1287. args = (1 2 3 4)
  ',
                   'results' => [ { 'args' => [ 1, 2, 3, 4 ], 's' => 10 } ]
                 }, 'GRID::Machine::Process::Result' );

  GRID::Machine::Process::Result objects are overloaded in a string context:
  stdout: Hello from process 1287. args = (1 2 3 4)
  stderr: Hello from process 1287

The following example uses the C<fork> method and C<waitall> to 
compute in parallel a numerical approach to the value of the number C<pi>:

  $ cat -n waitpi.pl 
     1  #!/usr/bin/perl -w
     2  use strict;
     3  use GRID::Machine;
     4  
     5  my $host = $ENV{GRID_REMOTE_MACHINE};
     6  my $machine = GRID::Machine->new( host => $host );
     7  
     8  my ($N, $np, $pi)  = (1000, 4, 0);
     9  for (0..$np-1) {
    10     $machine->fork( q{
    11         my ($id, $N, $np) = @_;
    12           
    13         my $sum = 0;
    14         for (my $i = $id; $i < $N; $i += $np) {
    15             my $x = ($i + 0.5) / $N;
    16             $sum += 4 / (1 + $x * $x);
    17         }
    18         $sum /= $N; 
    19      },
    20      args => [ $_, $N, $np ],
    21    );
    22  }
    23  
    24  $pi += $machine->waitall()->result for 1..$np;
    25  
    26  print "pi = $pi\n";

=head2  The C<async> method

The C<async> method it is quite similar to the fork method
but receives as arguments the  name of a L<GRID::Machine> method 
and the arguments for this method.
It executes asynchronously the method. 
It returns a L<GRID::Machine::Process> object.
Basically, the call

            $m->async($subname => @args) 

is equivalent to:



( run in 0.767 second using v1.01-cache-2.11-cpan-39bf76dae61 )