Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Re^2: Hobo with a bit of recursion

by Veltro (Hermit)
on Jun 17, 2018 at 16:23 UTC ( [id://1216815]=note: print w/replies, xml ) Need Help??


in reply to Re: Hobo with a bit of recursion
in thread Hobo with a bit of recursion

Hello marioroy,

Thanks for your excellent reply. Besides giving me a couple of very nice examples you also explained sharing to me and the importance of it. I start to see now that I definitively need to do some more studying regards this subject.

One of your answers (in italic below) leads me to another question regards sharing nested objects

>> "The tie statement does not deeply share key-values during construction. The way to shared nested hash/array structures is explicitly via the STORE method"

In case objects are shared that do not have STORE and FETCH methods, and they have nested methods and objects, does this mean that the methods cannot be reached and the objects don't get to be shared?

Example, Bar object has nested Foo object (inside hash key nestedFoo):

Foo and Bar definitions:

BEGIN { package Foo ; use strict ; use warnings ; sub new { my $class = shift ; my $this = { _var => 1, } ; bless $this, $class ; } sub task { # Long operation task Foo ~ 2 seconds my $this = shift ; print "Starting task Foo for $_[0]\n" ; sleep(2) ; ++$this->{ _var } ; print "Finished task Foo for $_[0]\n" ; } package Bar ; use strict ; use warnings ; sub new { my $class = shift ; # This is not very realistic code. # here it is just used as an # example to create an object that # contains a nested object my $this = { _var => 1, } ; $this->{ nestedFoo } = $_[0] ; bless $this, $class ; } sub task { # Long operation task Bar ~ 6 seconds my $this = shift ; print "Starting task Bar for $_[0]\n" ; sleep(6) ; ++$this->{ _var } ; print "Finished task Bar for $_[0]\n" ; } }

Main:

package main ; use strict ; use warnings ; use MCE::Shared ; use Data::Dumper ; my $foo = new Foo ; my $bar = new Bar( $foo ) ; # my $barShared = MCE::Shared->share( { module => 'Bar' }, $foo ) ; # or # from examples: my $ob = MCE::Shared->share( $blessed_object ); my $barSh = MCE::Shared->share( Bar->new( $foo ) ) ; print Dumper( $barSh->export ) . "\n" ; $barSh->task( 'Bar' ) ; # OK $barSh->{ nestedFoo }->task( 'Foo' ) ; # Not a HASH reference # Program died here $barSh->export->{ nestedFoo }->task( 'Foo' ) ; # OK, but not shared? __END__ $VAR1 = bless( { '_var' => 1, 'nestedFoo' => bless( { '_var' => 1 }, 'Foo' ) }, 'Bar' ); Starting task Bar for Bar Not a HASH reference at testHobo3.pl line 60, <__ANONIO__> line 1. Finished task Bar for Bar

Is there a way to 'get' the nestedFoo in shared context?

Is there a way to execute task for Foo without export?

edit: I forgot to mention the nested _var in each of the objects. What I mean with 'shared context' is that each _var become 2 inside of the share after the task methods have been executed.

Replies are listed 'Best First'.
Re^3: Hobo with a bit of recursion
by marioroy (Prior) on Jun 18, 2018 at 04:42 UTC

    Greetings Veltro,

    Yet another interesting use case :)

    Q & A

    In case objects are shared that do not have STORE and FETCH methods, and they have nested methods and objects, does this mean that the methods cannot be reached and the objects don't get to be shared?

    Is there a way to 'get' the nestedFoo in shared context?

    Is there a way to execute task for Foo without export?

    For shared objects, think of them as having an entry point into the shared-manager process. Important for shared-objects, in the case of MCE::Shared, is to pass arguments instead of dereferencing. Please note that calling a method on a shared-object is executed by the shared-manager where the data resides. For this use case, embed the shared-data object inside the class. That will allow workers to run in parallel and update shared-data accordingly.

    Demo 1: via Perl-like behavior

    Shown with mutex in the event multiple workers update the same key. Like in the prior post, the reason is because ++ involves two trips to the shared-manager process { FETCH and STORE }. I added an export routine to filter out the mutex handle.

    use strict; use warnings; package Foo { use MCE::Shared ; sub new { my $class = shift ; my $this = { } ; tie my %data, 'MCE::Shared', _var => 1 ; $this->{ _SHARED_DATA } = \%data ; $this->{ _MUTEX } = MCE::Mutex->new ; bless $this, $class ; } sub task { # Long operation task Foo ~ 2 seconds my $this = shift ; print "Starting task Foo for $_[0]\n" ; sleep 2 ; $this->{ _MUTEX }->enter( sub { ++$this->{ _SHARED_DATA }{ _var } ; }) ; print "Finished task Foo for $_[0]\n" ; } sub export { my $this = shift ; my %clone = %{ $this } ; delete $clone{ _MUTEX } ; return \%clone ; } } ; package Bar { use MCE::Shared ; use Scalar::Util 'blessed' ; sub new { my $class = shift ; # This is not very realistic code. # here it is just used as an # example to create an object that # contains a nested object my $this = { nestedFoo => $_[0] } ; tie my %data, 'MCE::Shared', _var => 1 ; $this->{ _SHARED_DATA } = \%data ; $this->{ _MUTEX } = MCE::Mutex->new ; bless $this, $class ; } sub task { my $this = shift ; if ( @_ == 2 ) { $this->{ $_[0] }->task( $_[1] ) ; return ; } # Long operation task Bar ~ 6 seconds print "Starting task Bar for $_[0]\n" ; sleep 6 ; $this->{ _MUTEX }->enter( sub { ++$this->{ _SHARED_DATA }{ _var } ; }) ; print "Finished task Bar for $_[0]\n" ; } sub export { my $this = shift ; my %clone = %{ $this } ; delete $clone{ _MUTEX } ; for ( keys %clone ) { next unless blessed( $clone{ $_ } ) ; next unless $clone{ $_ }->can('export') ; $clone{ $_ } = $clone{ $_ }->export ; } return \%clone ; } } ; package main ; use MCE::Hobo ; use Data::Dumper ; my $foo = Foo->new ; my $bar = Bar->new( $foo ) ; print Dumper( $bar->export ), "\n" ; mce_async { $bar->task('Bar') } ; mce_async { $bar->task('nestedFoo', 'Foo') } ; MCE::Hobo->waitall ; print "\n", Dumper( $bar->export ), "\n" ;

    Demo 2: using the OO interface

    This eliminates the mutex at the application level. Here, the export routine calls export on the shared-data object.

    use strict; use warnings; package Foo { use MCE::Shared ; sub new { my $class = shift ; my $this = { } ; $this->{ _SHARED_DATA } = MCE::Shared->hash( _var => 1 ) ; bless $this, $class ; } sub task { # Long operation task Foo ~ 2 seconds my $this = shift ; print "Starting task Foo for $_[0]\n" ; sleep 2 ; $this->{ _SHARED_DATA }->incr('_var') ; print "Finished task Foo for $_[0]\n" ; } sub export { my $this = shift ; my %clone = %{ $this } ; $clone{ _SHARED_DATA } = $this->{ _SHARED_DATA }->export( { unbless => 1 } ) ; return \%clone ; } } ; package Bar { use MCE::Shared ; use Scalar::Util 'blessed' ; sub new { my $class = shift ; # This is not very realistic code. # here it is just used as an # example to create an object that # contains a nested object my $this = { nestedFoo => $_[0] } ; $this->{ _SHARED_DATA } = MCE::Shared->hash( _var => 1 ) ; bless $this, $class ; } sub task { my $this = shift ; if ( @_ == 2 ) { $this->{ $_[0] }->task( $_[1] ) ; return ; } # Long operation task Bar ~ 6 seconds print "Starting task Bar for $_[0]\n" ; sleep 6 ; $this->{ _SHARED_DATA }->incr('_var') ; print "Finished task Bar for $_[0]\n" ; } sub export { my $this = shift ; my %clone = %{ $this } ; for ( keys %clone ) { next unless blessed( $clone{ $_ } ) ; next unless $clone{ $_ }->can('export') ; $clone{ $_ } = $clone{ $_ }->export( { unbless => 1 } ) ; } return \%clone ; } } ; package main ; use MCE::Hobo ; use Data::Dumper ; my $foo = Foo->new ; my $bar = Bar->new( $foo ) ; print Dumper( $bar->export ), "\n" ; mce_async { $bar->task('Bar') } ; mce_async { $bar->task('nestedFoo', 'Foo') } ; MCE::Hobo->waitall ; print "\n", Dumper( $bar->export ), "\n" ;

    Output

    $VAR1 = { '_SHARED_DATA' => { '_var' => 1 }, 'nestedFoo' => { '_SHARED_DATA' => { '_var' => 1 } } }; Starting task Bar for Bar Starting task Foo for Foo Finished task Foo for Foo Finished task Bar for Bar $VAR1 = { '_SHARED_DATA' => { '_var' => 2 }, 'nestedFoo' => { '_SHARED_DATA' => { '_var' => 2 } } };

    Regards, Mario

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1216815]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (5)
As of 2024-04-19 20:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found