From: Ted Zlatanov on
On Fri, 25 Jun 2010 01:14:11 -0700 (PDT) Peter Valdemar M�rch <4ux6as402(a)sneakemail.com> wrote:

PVM> On Jun 25, 3:16�am, Ben Morrow <b...(a)morrow.me.uk> wrote:
>> OK; how is this different from forks and forks::shared?

PVM> It is _much_ more similar to forks and forks::shared than to Coro.

PVM> While the forks and forks::shared API emulate the API of threads and
PVM> threads::shared (perfectly?), Parallel::Loops tries to emulate the
PVM> standard foreach and while loops as close as possible as in:

PVM> $pl->foreach(\@input, sub {
PVM> $output{$_} = do_some_hefty_calculation($_);
PVM> });

I like that syntax better personally than join() and detach().

PVM> I guess Parallel::Loops could have been written with forks and
PVM> forks::shared, and only provided syntactic sugar. (In fact it uses
PVM> Parallel::ForkManager and Tie::Hash/Tie::Array instead.)

`forks' brings in socket IPC which can be an issue. Your approach seems
a little cleaner IIUC.

Ted
From: Ben Morrow on

Quoth Ted Zlatanov <tzz(a)lifelogs.com>:
> On Fri, 25 Jun 2010 01:14:11 -0700 (PDT) Peter Valdemar M�rch
> <4ux6as402(a)sneakemail.com> wrote:
>
> PVM> On Jun 25, 3:16�am, Ben Morrow <b...(a)morrow.me.uk> wrote:
> >> OK; how is this different from forks and forks::shared?
>
> PVM> It is _much_ more similar to forks and forks::shared than to Coro.
>
> PVM> While the forks and forks::shared API emulate the API of threads and
> PVM> threads::shared (perfectly?), Parallel::Loops tries to emulate the
> PVM> standard foreach and while loops as close as possible as in:
>
> PVM> $pl->foreach(\@input, sub {
> PVM> $output{$_} = do_some_hefty_calculation($_);
> PVM> });
>
> I like that syntax better personally than join() and detach().

Personally I find

my %output :shared;

for my $i (@input) {
async {
$output{$i} = do_some_hefty_calculation($i);
}
}

somewhat clearer, but that's just a matter of taste. (With 5.10
presumably a 'my $_' would make $_ work too.)

> PVM> I guess Parallel::Loops could have been written with forks and
> PVM> forks::shared, and only provided syntactic sugar. (In fact it uses
> PVM> Parallel::ForkManager and Tie::Hash/Tie::Array instead.)
>
> `forks' brings in socket IPC which can be an issue. Your approach seems
> a little cleaner IIUC.

THe IPC has to be done *somehow*. Sockets are probably as reliable as
any other mechanism.

Ben

From: Peter Valdemar Mørch on
On Jun 26, 12:34 am, Ben Morrow <b...(a)morrow.me.uk> wrote:
> Personally I find
>
> my %output :shared;
>
> for my $i (@input) {
> async {
> $output{$i} = do_some_hefty_calculation($i);
> }
> }
>
> somewhat clearer, but that's just a matter of taste. (With 5.10
> presumably a 'my $_' would make $_ work too.)

In fact, I think that looks better too. I do have a few concerns:

* Having "my %output : shared" and just async without a
Parallel::Loops reference parameter inevitably leads to global
variables. I don't like them. One could have two different
calculations in different sections of the code, that don't need the
same variables "shared", so I'd prefer to have info about shared
variables associated with a specific Parallel::Loops instance. What do
you think?

* About the async {} instead of $pl->foreach: The implementation needs
to wait for the last loop to finish, and only continue after the '}'
after all the processes have finished. I don't know how to do that
unless something like:

for my $i (@input) {
# This fires up the parallel processes
$pl->async {
$output{$i} = do_some_hefty_calculation($i);
}
}
# This waits for them all to finish before continuing.
$pl->joinAll();

This syntax could easily co-exist with the $pl->foreach and $pl->while
syntax. I'm worried though that people will forget to call $pl-
>joinAll()! I guess one could also have async return some reference to
the actual forked process (pid comes to mind) and then $pl->join($pid)
to wait for it to finish.

Regardless, I now think $pl->share(\%output) is a better name than $pl-
>tieOutput(\%output)

The rest of this post is about "my %difficulties : with shared;" :-) -
this syntax is how (threads|forks)::shared does it too. I like it, but
don't yet understand how to implement it. Have looked at "perldoc
attributes" and experimented a little. In fact I could get attributes
like "Shared" (==ucfirst("shared")) to work. "xxshared" works, but
issues a warning, but "shared" simply doesn't work (perl 5.10). Also,
I guess it isn't possible for several packages to be "listening" for
attributes at the same time, as they'd step on each other's exports of
e.g. sub MODIFY_SCALAR_ATTRIBUTES, wouldn't they?

Here is a little snippet I wrote to experiment:

me(a)it:~> cat attributes.pl
#!perl -w
use strict;
use attributes;
use Data::Dumper;

sub MODIFY_SCALAR_ATTRIBUTES {
my ($pkg, $ref, $attributes) = @_;
print Dumper(\@_, attributes::get($ref));
return ();
}

my $shared : shared;
my $xshared : xshared;
my $Shared : Shared;

me(a)it:~> perl attributes.pl
$VAR1 = [
'main',
\undef
];
$VAR1 = [
'main',
\undef,
'xshared'
];
SCALAR package attribute may clash with future reserved word: xshared
at attributes.pl line 13
$VAR1 = [
'main',
\undef,
'Shared'
];
From: Peter Valdemar Mørch on
On Jun 25, 5:33 pm, Ted Zlatanov <t...(a)lifelogs.com> wrote:
> I like that syntax better personally than join() and detach().

Thanks for the support! :-)

> `forks' brings in socket IPC which can be an issue.  Your approach seems
> a little cleaner IIUC.

As Ben says, it has to be done somehow. I use a pipe behind the
scenes.

Peter
From: Ben Morrow on

Quoth =?ISO-8859-1?Q?Peter_Valdemar_M=F8rch?= <4ux6as402(a)sneakemail.com>:
> On Jun 26, 12:34 am, Ben Morrow <b...(a)morrow.me.uk> wrote:
> > Personally I find
> >
> > my %output :shared;
> >
> > for my $i (@input) {
> > async {
> > $output{$i} = do_some_hefty_calculation($i);
> > }
> > }
> >
> > somewhat clearer, but that's just a matter of taste. (With 5.10
> > presumably a 'my $_' would make $_ work too.)
>
> In fact, I think that looks better too. I do have a few concerns:
>
> * Having "my %output : shared" and just async without a
> Parallel::Loops reference parameter inevitably leads to global
> variables. I don't like them. One could have two different
> calculations in different sections of the code, that don't need the
> same variables "shared", so I'd prefer to have info about shared
> variables associated with a specific Parallel::Loops instance. What do
> you think?

They're not global. %output can be scoped as tightly as you like around
the async call: async takes a closure, so it will make available (either
shared or as copies) any lexicals in scope at the time. (This is why $_
won't work: it isn't a lexical.)

> * About the async {} instead of $pl->foreach: The implementation needs
> to wait for the last loop to finish, and only continue after the '}'
> after all the processes have finished. I don't know how to do that
> unless something like:
>
> for my $i (@input) {
> # This fires up the parallel processes
> $pl->async {
> $output{$i} = do_some_hefty_calculation($i);
> }
> }
> # This waits for them all to finish before continuing.
> $pl->joinAll();

Well, again using forks, you would write

my %output :shared;
my @thr;

for my $i (@input) {
push @thr, async {
$output{$i} = ...;
}
}
$_->join for @thr;

> This syntax could easily co-exist with the $pl->foreach and $pl->while
> syntax.

Not like that it can't, since methods don't have prototypes. If you want
a method call it would have to look like

$pl->async(sub { ... });

> I'm worried though that people will forget to call $pl-
> >joinAll()!

Stick it in DESTROY.

> I guess one could also have async return some reference to
> the actual forked process (pid comes to mind) and then $pl->join($pid)
> to wait for it to finish.
>
> Regardless, I now think $pl->share(\%output) is a better name than $pl-
> >tieOutput(\%output)
>
> The rest of this post is about "my %difficulties : with shared;" :-) -
> this syntax is how (threads|forks)::shared does it too. I like it, but
> don't yet understand how to implement it. Have looked at "perldoc
> attributes" and experimented a little. In fact I could get attributes
> like "Shared" (==ucfirst("shared")) to work. "xxshared" works, but
> issues a warning, but "shared" simply doesn't work (perl 5.10).

Yup. That's by design. Lowercase attributes are reserved to the core;
:shared, specifically, is handled internally as part of the threads
code, and is never seen by MODIFY_*_ATTRIBUTES. (Obviously it is
possible to hijack it, since forks manages to do so, but it can only be
done globally.)

> Also,
> I guess it isn't possible for several packages to be "listening" for
> attributes at the same time, as they'd step on each other's exports of
> e.g. sub MODIFY_SCALAR_ATTRIBUTES, wouldn't they?

That is certainly a possibility. IIRC Attribute::Handlers handles this
for you, since there's then only one MODIFY_*_ATTR sub to install.
Alternatively, keep a ref to the old sub (if there is one) and call it
if you don't see an attr you recognise.

Ben