Please find below various demonstrations. Increase the loop iteration from 1e5 to 1e6 and watch top or task manager.
#!/usr/bin/env perl
use strict;
use warnings;
use MCE::Hobo;
use MCE::Shared;
use Time::HiRes qw(time);
use feature qw(say);
my $number = MCE::Shared->scalar(0);
my $start = time;
MCE::Hobo->create('task', $_) for 1 .. 4;
MCE::Hobo->waitall;
printf "duration: %0.3f seconds\n", time - $start;
say "number: ", $number->get();
sub task {
my ($id) = @_;
say "Hobo $id started";
$number->incr() for 1 .. 100000;
say "Hobo $id ended";
}
__END__
Hobo 1 started
Hobo 2 started
Hobo 3 started
Hobo 4 started
Hobo 4 ended
Hobo 2 ended
Hobo 1 ended
Hobo 3 ended
duration: 0.872 seconds
number: 400000
Fetching data involves extra latency due to workers waiting for a response from the shared-manager process. No worries, it runs reasonably well for being a plain-Perl module.
sub task {
my ($id, $val) = @_;
say "Hobo $id started";
$val = $number->incr() for 1 .. 100000;
say "Hobo $id ended";
}
__END__
Hobo 1 started
Hobo 2 started
Hobo 3 started
Hobo 4 started
Hobo 4 ended
Hobo 3 ended
Hobo 1 ended
Hobo 2 ended
duration: 2.183 seconds
number: 400000
Dereferencing involving a fetch and store requires a mutex. Overhead goes up the roof. There's now a mutex lock, TIE STORE + FETCH (2 IPCs for that), and finally a mutex unlock.
#!/usr/bin/env perl
use strict;
use warnings;
use MCE::Hobo;
use MCE::Mutex;
use MCE::Shared;
use Time::HiRes qw(time);
use feature qw(say);
my $mutex = MCE::Mutex->new( impl => 'Channel' );
my $number = MCE::Shared->scalar(0);
my $start = time;
MCE::Hobo->create('task', $_) for 1 .. 4;
MCE::Hobo->waitall;
printf "duration: %0.3f seconds\n", time - $start;
say "number: ", $number->get();
sub task {
my ($id, $val) = @_;
say "Hobo $id started";
for ( 1 .. 100000 ) {
$mutex->lock;
$val = ++${ $number };
$mutex->unlock;
}
say "Hobo $id ended";
}
__END__
Hobo 1 started
Hobo 2 started
Hobo 3 started
Hobo 4 started
Hobo 2 ended
Hobo 1 ended
Hobo 4 ended
Hobo 3 ended
duration: 20.343 seconds
number: 400000
Let's remove dereferencing. Thus, mutex and OO only.
sub task {
my ($id, $val) = @_;
say "Hobo $id started";
for ( 1 .. 100000 ) {
$mutex->lock;
$val = $number->incr();
$mutex->unlock;
}
say "Hobo $id ended";
}
__END__
Hobo 1 started
Hobo 2 started
Hobo 3 started
Hobo 4 started
Hobo 3 ended
Hobo 4 ended
Hobo 1 ended
Hobo 2 ended
duration: 9.702 seconds
number: 400000
Summary
Performance is possible via the OO interface. Dereferencing is nice if you need it. Mutex is possible as well for synchronization. Any fetch from the shared-manager takes extra time. MCE::Shared is fully wantarray aware. Meaning, the MCE::Shared engine will only do extra stuff whenever needed, not more.
Regards, Mario.