NAME
MCE::Shared - MCE extension for sharing data between workers
VERSION
This document describes MCE::Shared version 1.699_006
SYNOPSIS
# OO construction
use MCE::Shared Sereal => 1;
my $ar = MCE::Shared->array( @list );
my $cv = MCE::Shared->condvar( 0 );
my $fh = MCE::Shared->handle( '>>', \*STDOUT );
my $ha = MCE::Shared->hash( @pairs );
my $oh = MCE::Shared->ordhash( @pairs );
my $qu = MCE::Shared->queue( await => 1, fast => 0 );
my $va = MCE::Shared->scalar( $value );
my $nu = MCE::Shared->sequence( $begin, $end, $step, $fmt );
my $ob = MCE::Shared->share( $blessed_object );
# Tie construction
use MCE::Flow;
use MCE::Shared Sereal => 1;
use feature 'say';
tie my $var, 'MCE::Shared', 'initial value';
tie my @ary, 'MCE::Shared', qw(a list of values);
tie my %has, 'MCE::Shared', (key1 => 'value', key2 => 'value');
tie my $cnt, 'MCE::Shared', 0;
tie my @foo, 'MCE::Shared';
tie my %bar, 'MCE::Shared';
my $m1 = MCE::Mutex->new;
mce_flow {
max_workers => 4
},
sub {
my ($mce) = @_;
my ($pid, $wid) = (MCE->pid, MCE->wid);
## Locking is required when multiple workers update the same element.
## This requires 2 trips to the manager process (fetch and store).
$m1->synchronize( sub {
$cnt += 1;
});
## Locking is not necessary when updating unique elements.
$foo[ $wid - 1 ] = $pid;
$bar{ $pid } = $wid;
return;
};
say "scalar : $cnt";
say " array : $_" for (@foo);
say " hash : $_ => $bar{$_}" for (sort keys %bar);
-- Output
scalar : 4
array : 37847
array : 37848
array : 37849
array : 37850
hash : 37847 => 1
hash : 37848 => 2
hash : 37849 => 3
hash : 37850 => 4
DESCRIPTION
This module provides data sharing for MCE supporting threads and processes.
MCE::Shared enables extra functionality on systems with IO::FDPass. Without it, MCE::Shared is unable to send file descriptors to the shared-manager process for <queue>, condvar, and possibly handle.
As of this writing, the IO::FDPass module is not a requirement for running MCE::Shared nor is the check made during installation. The reason is that IO::FDPass is not possible on Cygwin and not sure about AIX.
The following is a suggestion for systems without IO::FDPass. This restriction applies to queue, condvar, and handle only.
use MCE::Shared;
# Construct shared queue(s) and condvar(s) first.
# These contain GLOB handles - freezing not allowed.
my $q1 = MCE::Shared->queue();
my $q2 = MCE::Shared->queue();
my $cv1 = MCE::Shared->condvar();
my $cv2 = MCE::Shared->condvar();
# Start the shared-manager manually.
MCE::Shared->start();
# The shared-manager process knows of STDOUT, STDERR, STDIN
my $fh1 = MCE::Shared->handle(">>", \*STDOUT); # ok
my $fh2 = MCE::Shared->handle("<", "/path/to/sequence.fasta"); # ok
my $h1 = MCE::Shared->hash();
Otherwise, sharing is immediate and not delayed with IO::FDPass. It is not necessary to share queue and condvar first or worry about starting the shared-manager process.
use MCE::Shared;
my $h1 = MCE::Shared->hash(); # shares immediately
my $q1 = MCE::Shared->queue(); # IO::FDPass sends file descriptors
my $cv = MCE::Shared->condvar(); # IO::FDPass sends file descriptors
my $h2 = MCE::Shared->ordhash();
DATA SHARING
- array
- condvar
- handle
- hash
- ordhash
- queue
- scalar
- sequence
-
array,condvar,handle,hash,ordhash,queue,scalar, andsequenceare sugar syntax for constructing a shared object.# long form use MCE::Shared; use MCE::Shared::Array; use MCE::Shared::Hash; my $ar = MCE::Shared->share( MCE::Shared::Array->new() ); my $ha = MCE::Shared->share( MCE::Shared::Hash->new() ); # short form use MCE::Shared; my $ar = MCE::Shared->array( @list ); my $cv = MCE::Shared->condvar( 0 ); my $fh = MCE::Shared->handle( '>>', \*STDOUT ); my $ha = MCE::Shared->hash( @pairs ); my $oh = MCE::Shared->ordhash( @pairs ); my $qu = MCE::Shared->queue( await => 1, fast => 0 ); my $va = MCE::Shared->scalar( $value ); my $nu = MCE::Shared->sequence( $begin, $end, $step, $fmt ); - num_sequence
-
num_sequenceis an alias forsequence.
OBJECT SHARING
-
This class method transfers the blessed-object to the shared-manager process and returns a
MCE::Shared::Objectcontaining theSHARED_ID. The object must not contain anyGLOB's orCODE_REF's or the transfer will fail.Unlike
threads::shared, objects are not deeply shared. The shared object is accessable only through the underlying OO interface.use MCE::Shared; use Hash::Ordered; my ($ho_shared, $ho_unshared); $ho_shared = MCE::Shared->share( Hash::Ordered->new() ); $ho_shared->push( @pairs ); # OO interface only $ho_shared->merge( @pairs ); $ho_unshared = $ho_shared->export(); # back to unshared $ho_unshared = $ho_shared->destroy(); # including destructionThe following provide long and short forms for constructing a shared array, hash, or scalar object.
use MCE::Shared; use MCE::Shared::Array; # Loading helper classes is not necessary use MCE::Shared::Hash; # when using the shorter form. use MCE::Shared::Scalar; my $a1 = MCE::Shared->share( MCE::Shared::Array->new( @list ) ); my $a3 = MCE::Shared->share( [ @list ] ); # sugar syntax my $a2 = MCE::Shared->array( @list ); my $h1 = MCE::Shared->share( MCE::Shared::Hash->new( @pairs ) ); my $h3 = MCE::Shared->share( { @pairs } ); # sugar syntax my $h2 = MCE::Shared->hash( @pairs ); my $s1 = MCE::Shared->share( MCE::Shared::Scalar->new( 20 ) ); my $s2 = MCE::Shared->share( \do{ my $o = 20 } ); my $s4 = MCE::Shared->scalar( 20 );
PDL SHARING
- pdl_byte
- pdl_short
- pdl_ushort
- pdl_long
- pdl_longlong
- pdl_float
- pdl_double
- pdl_ones
- pdl_sequence
- pdl_zeroes
- pdl_indx
- pdl
-
pdl_byte,pdl_short,pdl_ushort,pdl_long,pdl_longlong,pdl_float,pdl_double,pdl_ones,pdl_sequence,pdl_zeroes,pdl_indx, andpdlare sugar syntax for PDL construction take place under the shared-manager process.use PDL; use PDL::IO::Storable; # must load for freezing/thawing use MCE::Shared; # must load MCE::Shared after PDL # not efficient from memory copy/transfer and unnecessary destruction my $ob1 = MCE::Shared->share( zeroes( 256, 256 ) ); # efficient my $ob1 = MCE::Shared->zeroes( 256, 256 ); - ins_inplace
-
The
ins_inplacemethod applies to shared PDL objects. It supports two forms for writing bits back into the PDL object residing under the shared-manager process.# --- action taken by the shared-manager process # ins_inplace( 2 args ): $this->slice( $arg1 ) .= $arg2; # ins_inplace( >2 args ): ins( inplace( $this ), $what, @coords ); # --- use case $o->ins_inplace( ":,$start:$stop", $result ); # 2 args $o->ins_inplace( $result, 0, $seq_n ); # >2 argsThe MCE-Cookbook on Github provides a couple working PDL demonstrations for further reading.
COMMON API
- blessed
-
Returns the real
blessedname, provided by the shared-manager process.use Scalar::Util qw(blessed); use MCE::Shared; use MCE::Shared::Ordhash; use Hash::Ordered; my $oh1 = MCE::Shared->share( MCE::Shared::Ordhash->new() ); my $oh2 = MCE::Shared->share( Hash::Ordered->new() ); print blessed($oh1), "\n"; # MCE::Shared::Object print blessed($oh2), "\n"; # MCE::Shared::Object print $oh1->blessed(), "\n"; # MCE::Shared::Ordhash print $oh2->blessed(), "\n"; # Hash::Ordered - destroy
-
Exports optionally, but destroys the shared object entirely from the shared-manager process.
my $exported_ob = $shared_ob->destroy(); $shared_ob; # becomes undef - export
-
Exports the shared object into a non-shared object. One must export when passing the shared object into any dump routine. Otherwise, the data
${ SHARED_ID }is all one will see.use MCE::Shared; use MCE::Shared::Ordhash; sub _dump { require Data::Dumper unless $INC{'Data/Dumper.pm'}; no warnings 'once'; local $Data::Dumper::Varname = 'VAR'; local $Data::Dumper::Deepcopy = 1; local $Data::Dumper::Indent = 1; local $Data::Dumper::Purity = 1; local $Data::Dumper::Sortkeys = 0; local $Data::Dumper::Terse = 0; print Data::Dumper::Dumper($_[0]) . "\n"; } # these do the same thing my $oh1 = MCE::Shared->share( MCE::Shared::Ordhash->new() ); my $oh2 = MCE::Shared->ordhash(); _dump($oh1); # ${ 1 } # SHARED_ID value _dump($oh2); # ${ 2 } _dump($oh1->export()); # actual structure and content _dump($oh2->export());exportcan optionally take a list of indices/keys for what to export. This applies to shared array, hash, and ordhash.use MCE::Shared; my $h1 = MCE::Shared->hash( # shared hash qw/ I Heard The Bluebirds Sing by Marty Robbins / # k v k v k v k v ); my $h2 = $h1->export( qw/ I The / ); # non-shared hash _dump($h2); __END__ $VAR1 = bless( { 'I' => 'Heard', 'The' => 'Bluebirds' }, 'MCE::Shared::Hash' ); - next
- prev
- reset
-
next,prev, andresetenables parallel iteration between workers for shared array, hash, ordhash, and sequence. Callresetafter running to start over. Workers may iterate either directionnextorprev.use MCE::Hobo; use MCE::Shared; my $ob = MCE::Shared->array( 'a' .. 'j' ); sub parallel { my ($id) = @_; while (defined (my $item = $ob->next)) { print "$id: $item\n"; sleep 1; } } MCE::Hobo->new( \¶llel, $_ ) for 1 .. 3; # ... do other work ... $_->join() for MCE::Hobo->list(); -- Output 1: a 2: b 3: c 2: f 1: d 3: e 2: g 3: i 1: h 2: jThere are two forms for iterating through a shared hash or ordhash object.
use MCE::Hobo; use MCE::Shared; my $ob = MCE::Shared->ordhash( map {( "key_$_" => "val_$_" )} "a" .. "j" ); sub iter1 { my ($id) = @_; while ( my ($key, $val) = $ob->next ) { print "$id: $key => $val\n"; sleep 1; } } sub iter2 { my ($id) = @_; while ( defined (my $val = $ob->prev) ) { print "$id: $val\n"; sleep 1; } } MCE::Hobo->new(\&iter1, $_) for 1 .. 3; $_->join() for MCE::Hobo->list(); $ob->reset(); MCE::Hobo->new(\&iter2, $_) for 1 .. 3; $_->join() for MCE::Hobo->list();The shared-manager process will iterate orderly, but there is no guarantee for the amount of time required by workers. Thus, output may not be ordered.
-- Output 1: key_a => val_a 2: key_b => val_b 3: key_c => val_c 1: key_d => val_d 2: key_f => val_f 3: key_e => val_e 3: key_i => val_i 2: key_g => val_g 1: key_h => val_h 3: key_j => val_j 1: val_j 2: val_i 3: val_h 1: val_g 3: val_e 2: val_f 3: val_d 2: val_b 1: val_c 2: val_a - dset
- dmerge
- dpush
- dunshift
-
Deep-sharing non-blessed structure(s) is possible with
dset,dmerge,dpush, anddunshift. These do the same thing as their counterpartsset,merge,push, andunshift. These methods traverse the list or hash recursively and covert non-blessed deeply-structures to shared objects.
SERVER API
- start
-
Starts the shared-manager process. This is done automatically.
MCE::Shared->start(); - stop
-
Stops the shared-manager process wiping all shared data content. This is not typically done by the user, but rather by END automatically when the script terminates.
MCE::Shared->stop(); - init
-
This is called automatically by each MCE/Hobo worker immediately after being spawned for selection of 1 of 8 data channels. The effect is extra parallelism during inter-process communication. The ID (optionally - must be an integer) is modded with 8 in a round-robin fashion.
MCE::Shared->init(); MCE::Shared->init( ID );
INDEX
AUTHOR
Mario E. Roy, <marioeroy AT gmail DOT com>