line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package subs::parallel;
|
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
38605
|
use warnings;
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
64
|
|
4
|
2
|
|
|
2
|
|
11
|
use strict;
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
42
|
|
5
|
|
|
|
|
|
|
|
6
|
2
|
|
|
2
|
|
39114
|
use threads;
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
use vars qw/@ISA @EXPORT $AUTOLOAD/;
|
8
|
|
|
|
|
|
|
use Attribute::Handlers;
|
9
|
|
|
|
|
|
|
use Scalar::Util qw/set_prototype/;
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
subs::parallel - enables subroutines to seamlessly run in parallel
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 VERSION
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
Version 0.09
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=cut
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
require Exporter;
|
22
|
|
|
|
|
|
|
@ISA = qw(Exporter);
|
23
|
|
|
|
|
|
|
@EXPORT = qw(parallelize parallelize_sub parallelize_coderef);
|
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
our $VERSION = '0.09';
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
use overload
|
28
|
|
|
|
|
|
|
'""' => \&_deref,
|
29
|
|
|
|
|
|
|
'0+' => \&_deref,
|
30
|
|
|
|
|
|
|
'bool'=> \&_deref,
|
31
|
|
|
|
|
|
|
'${}' => \&_deref,
|
32
|
|
|
|
|
|
|
'@{}' => \&_deref,
|
33
|
|
|
|
|
|
|
'%{}' => \&_deref,
|
34
|
|
|
|
|
|
|
'&{}' => \&_deref,
|
35
|
|
|
|
|
|
|
'*{}' => \&_deref,
|
36
|
|
|
|
|
|
|
fallback => 1;
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
use subs::parallel;
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub foo : Parallel {
|
43
|
|
|
|
|
|
|
# foo runs in parallel
|
44
|
|
|
|
|
|
|
}
|
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
parallelize_sub('bar');
|
47
|
|
|
|
|
|
|
# subroutine named bar now runs in parallel
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
my $foo = foo(); # returns immediately
|
50
|
|
|
|
|
|
|
my $bar = bar(); # also returns immediately
|
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# now it might block waiting for both to finish
|
53
|
|
|
|
|
|
|
if ($foo == $bar) {
|
54
|
|
|
|
|
|
|
...
|
55
|
|
|
|
|
|
|
}
|
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
my $baz = parallelize { ... code ... }; # returns immediately
|
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
...
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
print "baz: $baz\n"; # if it's still running, blocks until it finishes
|
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# it can be done to anonymous subs or any other coderefs too
|
66
|
|
|
|
|
|
|
my $anon = sub { ... more code ... };
|
67
|
|
|
|
|
|
|
my $parallel_coderef = parallelize_coderef($anon);
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
my $foobar = $parallel_coderef->('arg'); # returns immediately
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
...
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# sub should return an object, no problem
|
74
|
|
|
|
|
|
|
$foobar->do_something_else(); # blocks until it finishes running
|
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
This module gives Perl programmers the ability to easily and conveniently
|
79
|
|
|
|
|
|
|
create multi-threaded applications through B.
|
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
Parallel subroutines are just plain old subroutines which happen to run in
|
82
|
|
|
|
|
|
|
another thread. When called, they return immediately to the calling thread but
|
83
|
|
|
|
|
|
|
keep running in another. When its return value is needed somewhere, the
|
84
|
|
|
|
|
|
|
returned value is transparently fetched. If the thread is still running, the
|
85
|
|
|
|
|
|
|
code blocks waiting for it to finish (since the program can't go on without a
|
86
|
|
|
|
|
|
|
value and keep being transparent).
|
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
So, as it's possible to notice, the module interface aims to be as simple
|
89
|
|
|
|
|
|
|
as possible. In fact, it works in such a way that, aside from the
|
90
|
|
|
|
|
|
|
I directives, you wouldn't be able to tell it's a multi-threaded
|
91
|
|
|
|
|
|
|
application. All the thread handling (which isn't I complicated, really)
|
92
|
|
|
|
|
|
|
is done automagically.
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
It should work for anything that's thread safe - even for subroutines whose
|
95
|
|
|
|
|
|
|
return values are not usually available across thread boundaries (for example,
|
96
|
|
|
|
|
|
|
usually, you can't C an object, but this module makes it possible to
|
97
|
|
|
|
|
|
|
return them without any problems, provided they're thread safe).
|
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=head1 MOTIVATION
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
The main reason behind this module was the fact that Perl threads are not
|
102
|
|
|
|
|
|
|
widely used. Some could argue that this might happen because Perl threads are
|
103
|
|
|
|
|
|
|
not very practical to use. Others could say that the restrictions imposed by
|
104
|
|
|
|
|
|
|
the use of threads (you can't pass arbitrary data structures between threads).
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
The latter issue is out of my reach. But, through the use of already existing
|
107
|
|
|
|
|
|
|
features, it was possible to mask it a little bit. So you can return anything
|
108
|
|
|
|
|
|
|
from your parallelized subroutines, but this is just some maybe unknown feature
|
109
|
|
|
|
|
|
|
of Cjoin>.
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
The first issue is the main aim of this module: provide an extremely simple way
|
112
|
|
|
|
|
|
|
to make multi-threaded applications. Along this near-future reality of a
|
113
|
|
|
|
|
|
|
majority of dual-core computers, multi-threading might become the factor that
|
114
|
|
|
|
|
|
|
distiguishes good from bad software.
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
But I would be dishonest if I didn't note that some part of the effort was
|
117
|
|
|
|
|
|
|
driven by the will to prove it could be done in Perl.
|
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=head1 ATTRIBUTE HANDLING
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
The most practical way of using this module's features is through attrubutes.
|
122
|
|
|
|
|
|
|
This snippet ilustrates how to do it:
|
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
use subs::parallel;
|
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
sub foobar : Parallel {
|
127
|
|
|
|
|
|
|
# do stuff
|
128
|
|
|
|
|
|
|
}
|
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
That way, C is declared as a B. This should have
|
131
|
|
|
|
|
|
|
exactly the same effect as using the C below, but is cleaner
|
132
|
|
|
|
|
|
|
and more convenient.
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=head1 EXPORTS
|
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
The C, C and C subroutines
|
137
|
|
|
|
|
|
|
are exported. If you have problems with that, you're free to:
|
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
use subs::parallel ();
|
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=head1 FUNCTIONS
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
All the three functions available work similarly, implementing the idea of
|
144
|
|
|
|
|
|
|
B as explained above. Nevertheless, here's a brief
|
145
|
|
|
|
|
|
|
explanation of each of them.
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=head2 parallelize { BLOCK }
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
Starts running the specified block of code in parallel B.
|
150
|
|
|
|
|
|
|
The snippet below ilustrates this concept:
|
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
use subs::parallel;
|
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
my $foo = parallelize {
|
155
|
|
|
|
|
|
|
# do stuff here
|
156
|
|
|
|
|
|
|
};
|
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
my $bar = parallelize {
|
159
|
|
|
|
|
|
|
# do even more stuff
|
160
|
|
|
|
|
|
|
};
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
# now we wait for them to finish
|
163
|
|
|
|
|
|
|
print "$foo, $bar\n";
|
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=cut
|
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# parallelizes and runs a block of code / coderef
|
168
|
|
|
|
|
|
|
sub parallelize (&) { parallelize_coderef(shift)->() }
|
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=head2 parallelize_sub(STRING)
|
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
Transforms the named subroutine into a B. After this
|
173
|
|
|
|
|
|
|
modification, every it's called, it will run inside another thread and return
|
174
|
|
|
|
|
|
|
immediately to the caller.
|
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
The snippet below ilustrates this concept:
|
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
use subs::parallel;
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub blocking_stuff {
|
181
|
|
|
|
|
|
|
# do blocking stuff
|
182
|
|
|
|
|
|
|
}
|
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
blocking_stuff(); # this blocks
|
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
parallelize_sub('blocking_stuff');
|
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
blocking_stuff();
|
189
|
|
|
|
|
|
|
# now it returns immediately and the return values are discarded
|
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
Note that, you can I named subroutines inside other packages:
|
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
parallelize_sub('Other::Package::function');
|
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=cut
|
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# parallelizing subroutines by name
|
198
|
|
|
|
|
|
|
sub parallelize_sub {
|
199
|
|
|
|
|
|
|
my ($sub) = @_;
|
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
# only prepend caller package if it's fully qualified
|
202
|
|
|
|
|
|
|
# allows easy parallelizing of subroutines inside other packages
|
203
|
|
|
|
|
|
|
if ($sub !~ /::/) {
|
204
|
|
|
|
|
|
|
my ($caller) = caller();
|
205
|
|
|
|
|
|
|
$sub = join('::', $caller, $sub);
|
206
|
|
|
|
|
|
|
}
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# we don't want nasty warnings - but don't try this at home
|
209
|
|
|
|
|
|
|
no strict 'refs';
|
210
|
|
|
|
|
|
|
no warnings 'redefine';
|
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
croak("can't parallelize non-existant subroutine") unless defined *{$sub}{CODE};
|
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
# keeps the prototype
|
215
|
|
|
|
|
|
|
*$sub = &set_prototype(parallelize_coderef(\&$sub), prototype($sub));
|
216
|
|
|
|
|
|
|
}
|
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
=head2 parallelize_coderef(CODEREF)
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
Returns a parallelized version of the given CODEREF. This function is used
|
221
|
|
|
|
|
|
|
internally to implement the other two functions explained above.
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
my $code = sub { ... }
|
224
|
|
|
|
|
|
|
my $parallel = parallelize_coderef($code);
|
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
my $return = $parallel->(@args); # runs in another thread
|
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=cut
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# returns a new coderef: a parallelized version of the original coderef
|
231
|
|
|
|
|
|
|
# the original is *not* modified
|
232
|
|
|
|
|
|
|
sub parallelize_coderef {
|
233
|
|
|
|
|
|
|
my ($coderef) = @_;
|
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
return sub {
|
236
|
|
|
|
|
|
|
# this is the simple trick which makes this module work
|
237
|
|
|
|
|
|
|
my $scalar = threads->create($coderef, @_);
|
238
|
|
|
|
|
|
|
bless {thread => $scalar, caller => threads->tid}, __PACKAGE__;
|
239
|
|
|
|
|
|
|
};
|
240
|
|
|
|
|
|
|
}
|
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# support for parallelizing through subroutine attributes
|
243
|
|
|
|
|
|
|
sub UNIVERSAL::Parallel : ATTR(CODE) {
|
244
|
|
|
|
|
|
|
# for completeness sake, let's have the whole prototype
|
245
|
|
|
|
|
|
|
my ($caller, $symtable, $coderef, $attr, $data, $phase) = @_;
|
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
no warnings 'redefine';
|
248
|
|
|
|
|
|
|
# keeps the prototype
|
249
|
|
|
|
|
|
|
*$symtable = &set_prototype(parallelize_coderef($coderef), prototype($coderef));
|
250
|
|
|
|
|
|
|
}
|
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# the overload handler
|
253
|
|
|
|
|
|
|
sub _deref {
|
254
|
|
|
|
|
|
|
my $class = CORE::ref $_[0];
|
255
|
|
|
|
|
|
|
# work-around in order to support scalar refs - yes, it's kinda ugly
|
256
|
|
|
|
|
|
|
# the alternative would be Acme::Damn but I feel kinda bad using Acme modules
|
257
|
|
|
|
|
|
|
bless $_[0], "${class}::NoOverload";
|
258
|
|
|
|
|
|
|
if (CORE::ref($_[0]->{thread}) eq 'threads') {
|
259
|
|
|
|
|
|
|
$_[0] = $_[0]->{thread}->join;
|
260
|
|
|
|
|
|
|
}
|
261
|
|
|
|
|
|
|
else {
|
262
|
|
|
|
|
|
|
# just in case - should never get here
|
263
|
|
|
|
|
|
|
croak(__PACKAGE__ . " object doesn't reference a threads object - something really bad happened");
|
264
|
|
|
|
|
|
|
}
|
265
|
|
|
|
|
|
|
return $_[0];
|
266
|
|
|
|
|
|
|
}
|
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
# provide method calling support
|
269
|
|
|
|
|
|
|
sub AUTOLOAD {
|
270
|
|
|
|
|
|
|
# make errors appear to come from the caller
|
271
|
|
|
|
|
|
|
local $SIG{__DIE__} = sub { goto &croak };
|
272
|
|
|
|
|
|
|
(my $sub = $AUTOLOAD) =~ s/.*:://;
|
273
|
|
|
|
|
|
|
$_[0] = _deref($_[0]);
|
274
|
|
|
|
|
|
|
# unfortunately, if we used goto CODEREF, the call wouldn't be made as a
|
275
|
|
|
|
|
|
|
# method and warnings wouldn't be transparent. so, we prefer messing up the
|
276
|
|
|
|
|
|
|
# caller stack - which is not that used anyway, aside from instrospection
|
277
|
|
|
|
|
|
|
# modules.
|
278
|
|
|
|
|
|
|
shift->$sub(@_);
|
279
|
|
|
|
|
|
|
}
|
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
sub croak {
|
282
|
|
|
|
|
|
|
# somehow, local $SIG handlers are not actually locally scoped
|
283
|
|
|
|
|
|
|
# this makes sure we get other possibly fatal errors
|
284
|
|
|
|
|
|
|
local $SIG{__DIE__} = '';
|
285
|
|
|
|
|
|
|
(my $err = shift) =~ s/ at [^ ]+ line (?:\d+).?\n//;
|
286
|
|
|
|
|
|
|
require Carp;
|
287
|
|
|
|
|
|
|
Carp::croak($err);
|
288
|
|
|
|
|
|
|
}
|
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
# magic destructor!
|
291
|
|
|
|
|
|
|
# ok, ok... it just detaches the thread if we go out of scope.
|
292
|
|
|
|
|
|
|
# BUT ONLY IF we're the original caller of the thread
|
293
|
|
|
|
|
|
|
# this is a work-around for a strange behaviour of the perl threads implementation
|
294
|
|
|
|
|
|
|
sub DESTROY {
|
295
|
|
|
|
|
|
|
my $class = CORE::ref($_[0]);
|
296
|
|
|
|
|
|
|
bless $_[0], "${class}::NoOverload";
|
297
|
|
|
|
|
|
|
if (CORE::ref($_[0]->{thread}) eq 'threads' && $_[0]->{caller} == threads->tid) {
|
298
|
|
|
|
|
|
|
$_[0]->{thread}->detach;
|
299
|
|
|
|
|
|
|
}
|
300
|
|
|
|
|
|
|
}
|
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# provide overriden ref() function
|
303
|
|
|
|
|
|
|
sub ref ($) {
|
304
|
|
|
|
|
|
|
return CORE::ref($_[0]) if CORE::ref($_[0]) ne __PACKAGE__;
|
305
|
|
|
|
|
|
|
return CORE::ref($_[0]->_deref);
|
306
|
|
|
|
|
|
|
}
|
307
|
|
|
|
|
|
|
*CORE::GLOBAL::ref = \&ref;
|
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
1;
|
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# ok, i didn't tie anything. oh well, can't use them all...
|
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
=head1 INTERACTION WITH OTHER MODULES
|
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
The only B issue is between this module and L. When using
|
316
|
|
|
|
|
|
|
L the C attribute seems to be broken. This is probably due
|
317
|
|
|
|
|
|
|
to L trying to process every possible attribute, but I'm not really
|
318
|
|
|
|
|
|
|
sure. Patches are welcome.
|
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
There's a simple workaround. Instead of writing:
|
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub foo : Parallel {
|
323
|
|
|
|
|
|
|
# code here
|
324
|
|
|
|
|
|
|
}
|
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
Use the slightly more verbose:
|
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
sub foo {
|
329
|
|
|
|
|
|
|
# code here
|
330
|
|
|
|
|
|
|
}
|
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
parallelize_sub('foo');
|
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
That should work in all cases.
|
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
=head1 CAVEATS
|
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
Currently, the parallel subroutines will always be called in scalar context.
|
339
|
|
|
|
|
|
|
There are plans for changing this in the future but, for now, if multiple
|
340
|
|
|
|
|
|
|
return values are needed, consider wrapping them around an array ref (this
|
341
|
|
|
|
|
|
|
feature would require adding the Want module as a dependency).
|
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
In order for objects to survice across threads, both the calling and the
|
344
|
|
|
|
|
|
|
executing thread must have its class properly included. This means that you
|
345
|
|
|
|
|
|
|
can't require a module only inside a subroutine and then return an object
|
346
|
|
|
|
|
|
|
blessed into that class to the calling thread.
|
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
You shouldn't pass to another thread/parallelized subroutines previous return
|
349
|
|
|
|
|
|
|
values from other parallelized subroutines without reading their values. And,
|
350
|
|
|
|
|
|
|
while you can get away with it, it's probably too much rope to hang yourself on
|
351
|
|
|
|
|
|
|
when things start to get ugly. This might be changed in the future, but would
|
352
|
|
|
|
|
|
|
require some sort of explicit synchronization through shared variables.
|
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
Also, there's no way to tell if a parallelized subroutine is still running or
|
355
|
|
|
|
|
|
|
not. This probably will be changed in the future but, unfortunately, will
|
356
|
|
|
|
|
|
|
require either a minimalistic approach using some simple shared variables or
|
357
|
|
|
|
|
|
|
the use of Thread::Running, which would be another dependency and ends up using
|
358
|
|
|
|
|
|
|
shared variables anyway.
|
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
The caller stack may behave in a non expected manner. When calling returned
|
361
|
|
|
|
|
|
|
object's methods, there will be an extra level in the stack, representing
|
362
|
|
|
|
|
|
|
C magic - the third form of C couldn't be used since that way
|
363
|
|
|
|
|
|
|
if the user called a non-existant method, he wouldn't get the default warning.
|
364
|
|
|
|
|
|
|
In the future, maybe this will be configurable so that if you need to rely on
|
365
|
|
|
|
|
|
|
the caller stack, you can make this trade-off.
|
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
If the I subroutine dies, you won't get any warnings on notices
|
368
|
|
|
|
|
|
|
of any kind. It would be like it returned C. This might change in the
|
369
|
|
|
|
|
|
|
future.
|
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
C is overriden. This may be an issue if there are other
|
372
|
|
|
|
|
|
|
modules in use which override it too. In the future, there may be a switch to
|
373
|
|
|
|
|
|
|
disable this.
|
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=head1 BUGS
|
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
Besides the CAVEATS (which some people might consider to be bugs) there are no
|
378
|
|
|
|
|
|
|
known bugs.
|
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
Please report any bugs or feature requests to
|
381
|
|
|
|
|
|
|
C, or through the web interface at
|
382
|
|
|
|
|
|
|
L.
|
383
|
|
|
|
|
|
|
I will be notified, and then you'll automatically be notified of progress on
|
384
|
|
|
|
|
|
|
your bug as I make changes.
|
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
=head1 AUTHOR
|
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
Nilson Santos F. Jr., C<< >>
|
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE
|
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
Copyright (C) 2005-2015 Nilson Santos Figueiredo Junior.
|
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it
|
395
|
|
|
|
|
|
|
under the same terms as Perl itself.
|
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=head1 SEE ALSO
|
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
L
|
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=cut
|
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
1; # End of subs::parallel
|