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 )