File Coverage

blib/lib/MCE/Map.pm
Criterion Covered Total %
statement 178 233 76.3
branch 78 160 48.7
condition 24 55 43.6
subroutine 16 19 84.2
pod 5 5 100.0
total 301 472 63.7


line stmt bran cond sub pod time code
1             ###############################################################################
2             ## ----------------------------------------------------------------------------
3             ## Parallel map model similar to the native map function.
4             ##
5             ###############################################################################
6              
7             package MCE::Map;
8              
9 4     4   259711 use strict;
  4         28  
  4         122  
10 4     4   20 use warnings;
  4         4  
  4         105  
11              
12 4     4   16 no warnings qw( threads recursion uninitialized );
  4         5  
  4         195  
13              
14             our $VERSION = '1.887';
15              
16             ## no critic (BuiltinFunctions::ProhibitStringyEval)
17             ## no critic (Subroutines::ProhibitSubroutinePrototypes)
18             ## no critic (TestingAndDebugging::ProhibitNoStrict)
19              
20 4     4   22 use Scalar::Util qw( looks_like_number weaken );
  4         5  
  4         209  
21 4     4   1503 use MCE;
  4         11  
  4         23  
22              
23             our @CARP_NOT = qw( MCE );
24              
25             my $_tid = $INC{'threads.pm'} ? threads->tid() : 0;
26              
27             sub CLONE {
28 0 0   0   0 $_tid = threads->tid() if $INC{'threads.pm'};
29             }
30              
31             ###############################################################################
32             ## ----------------------------------------------------------------------------
33             ## Import routine.
34             ##
35             ###############################################################################
36              
37             my ($_MCE, $_def, $_params, $_prev_c, $_tag) = ({}, {}, {}, {}, 'MCE::Map');
38              
39             sub import {
40 4     4   48 my ($_class, $_pkg) = (shift, caller);
41              
42 4         15 my $_p = $_def->{$_pkg} = {
43             MAX_WORKERS => 'auto',
44             CHUNK_SIZE => 'auto',
45             };
46              
47             ## Import functions.
48 4 50       13 if ($_pkg !~ /^MCE::/) {
49 4     4   27 no strict 'refs'; no warnings 'redefine';
  4     4   8  
  4         109  
  4         17  
  4         7  
  4         9216  
50 4         7 *{ $_pkg.'::mce_map_f' } = \&run_file;
  4         23  
51 4         8 *{ $_pkg.'::mce_map_s' } = \&run_seq;
  4         12  
52 4         7 *{ $_pkg.'::mce_map' } = \&run;
  4         13  
53             }
54              
55             ## Process module arguments.
56 4         15 while ( my $_argument = shift ) {
57 0         0 my $_arg = lc $_argument;
58              
59 0 0       0 $_p->{MAX_WORKERS} = shift, next if ( $_arg eq 'max_workers' );
60 0 0       0 $_p->{CHUNK_SIZE} = shift, next if ( $_arg eq 'chunk_size' );
61 0 0       0 $_p->{TMP_DIR} = shift, next if ( $_arg eq 'tmp_dir' );
62 0 0       0 $_p->{FREEZE} = shift, next if ( $_arg eq 'freeze' );
63 0 0       0 $_p->{THAW} = shift, next if ( $_arg eq 'thaw' );
64 0 0       0 $_p->{INIT_RELAY} = shift, next if ( $_arg eq 'init_relay' );
65 0 0       0 $_p->{USE_THREADS} = shift, next if ( $_arg eq 'use_threads' );
66              
67             ## Sereal 3.015+, if available, is used automatically by MCE 1.8+.
68 0 0       0 if ( $_arg eq 'sereal' ) {
69 0 0       0 if ( shift eq '0' ) {
70 0         0 require Storable;
71 0         0 $_p->{FREEZE} = \&Storable::freeze;
72 0         0 $_p->{THAW} = \&Storable::thaw;
73             }
74 0         0 next;
75             }
76              
77 0         0 _croak("Error: ($_argument) invalid module option");
78             }
79              
80 4         19 $_p->{MAX_WORKERS} = MCE::_parse_max_workers($_p->{MAX_WORKERS});
81              
82 4         16 MCE::_validate_number($_p->{MAX_WORKERS}, 'MAX_WORKERS', $_tag);
83             MCE::_validate_number($_p->{CHUNK_SIZE}, 'CHUNK_SIZE', $_tag)
84 4 50       11 unless ($_p->{CHUNK_SIZE} eq 'auto');
85              
86 4         49 return;
87             }
88              
89             ###############################################################################
90             ## ----------------------------------------------------------------------------
91             ## Gather callback for storing by chunk_id => chunk_ref into a hash.
92             ##
93             ###############################################################################
94              
95             my ($_total_chunks, %_tmp);
96              
97             sub _gather {
98              
99 37     37   68 my ($_chunk_id, $_data_ref) = @_;
100              
101 37         101 $_tmp{$_chunk_id} = $_data_ref;
102 37         103 $_total_chunks++;
103              
104 37         89 return;
105             }
106              
107             ###############################################################################
108             ## ----------------------------------------------------------------------------
109             ## Init and finish routines.
110             ##
111             ###############################################################################
112              
113             sub init (@) {
114              
115 3 50 33 3 1 369 shift if (defined $_[0] && $_[0] eq 'MCE::Map');
116 3         21 my $_pkg = "$$.$_tid.".caller();
117              
118 3 50       21 $_params->{$_pkg} = (ref $_[0] eq 'HASH') ? shift : { @_ };
119              
120             _croak("$_tag: (HASH) not allowed as input by this MCE model")
121 3 50       12 if ( ref $_params->{$_pkg}{input_data} eq 'HASH' );
122              
123 3         6 @_ = ();
124              
125 3         6 return;
126             }
127              
128             sub finish (@) {
129              
130 7 50 33 7 1 1114 shift if (defined $_[0] && $_[0] eq 'MCE::Map');
131 7 100       43 my $_pkg = (defined $_[0]) ? shift : "$$.$_tid.".caller();
132              
133 7 100 66     65 if ( $_pkg eq 'MCE' ) {
    100          
134 4         6 for my $_k ( keys %{ $_MCE } ) { MCE::Map->finish($_k, 1); }
  4         30  
  2         46  
135             }
136             elsif ( $_MCE->{$_pkg} && $_MCE->{$_pkg}{_init_pid} eq "$$.$_tid" ) {
137 1 50       19 $_MCE->{$_pkg}->shutdown(@_) if $_MCE->{$_pkg}{_spawned};
138 1         4 $_total_chunks = undef, undef %_tmp;
139              
140 1         8 delete $_prev_c->{$_pkg};
141 1         12 delete $_MCE->{$_pkg};
142             }
143              
144 7         19 @_ = ();
145              
146 7         17 return;
147             }
148              
149             ###############################################################################
150             ## ----------------------------------------------------------------------------
151             ## Parallel map with MCE -- file.
152             ##
153             ###############################################################################
154              
155             sub run_file (&@) {
156              
157 2 50 33 2 1 2596 shift if (defined $_[0] && $_[0] eq 'MCE::Map');
158              
159 2         5 my $_code = shift; my $_file = shift;
  2         11  
160 2         10 my $_pid = "$$.$_tid.".caller();
161              
162 2 50       9 if (defined (my $_p = $_params->{$_pid})) {
163 2 50       7 delete $_p->{input_data} if (exists $_p->{input_data});
164 2 50       5 delete $_p->{sequence} if (exists $_p->{sequence});
165             }
166             else {
167 0         0 $_params->{$_pid} = {};
168             }
169              
170 2 100 66     135 if (defined $_file && ref $_file eq '' && $_file ne '') {
    50 66        
      33        
171 1 50       28 _croak("$_tag: ($_file) does not exist") unless (-e $_file);
172 1 50       13 _croak("$_tag: ($_file) is not readable") unless (-r $_file);
173 1 50       11 _croak("$_tag: ($_file) is not a plain file") unless (-f $_file);
174 1         15 $_params->{$_pid}{_file} = $_file;
175             }
176             elsif (ref $_file eq 'SCALAR' || ref($_file) =~ /^(?:GLOB|FileHandle|IO::)/) {
177 1         5 $_params->{$_pid}{_file} = $_file;
178             }
179             else {
180 0         0 _croak("$_tag: (file) is not specified or valid");
181             }
182              
183 2         5 @_ = ();
184              
185 2         6 return run($_code);
186             }
187              
188             ###############################################################################
189             ## ----------------------------------------------------------------------------
190             ## Parallel map with MCE -- sequence.
191             ##
192             ###############################################################################
193              
194             sub run_seq (&@) {
195              
196 1 50 33 1 1 957 shift if (defined $_[0] && $_[0] eq 'MCE::Map');
197              
198 1         3 my $_code = shift;
199 1         6 my $_pid = "$$.$_tid.".caller();
200              
201 1 50       4 if (defined (my $_p = $_params->{$_pid})) {
202 1 50       3 delete $_p->{input_data} if (exists $_p->{input_data});
203 1 50       3 delete $_p->{_file} if (exists $_p->{_file});
204             }
205             else {
206 0         0 $_params->{$_pid} = {};
207             }
208              
209 1         2 my ($_begin, $_end);
210              
211 1 50 33     7 if (ref $_[0] eq 'HASH') {
    50          
    50          
212 0         0 $_begin = $_[0]->{begin}, $_end = $_[0]->{end};
213 0         0 $_params->{$_pid}{sequence} = $_[0];
214             }
215             elsif (ref $_[0] eq 'ARRAY') {
216 0 0 0     0 if (@{ $_[0] } > 3 && $_[0]->[3] =~ /\d$/) {
  0         0  
217 0         0 $_begin = $_[0]->[0], $_end = $_[0]->[-1];
218 0         0 $_params->{$_pid}{sequence} = [ $_[0]->[0], $_[0]->[-1] ];
219             }
220             else {
221 0         0 $_begin = $_[0]->[0], $_end = $_[0]->[1];
222 0         0 $_params->{$_pid}{sequence} = $_[0];
223             }
224             }
225             elsif (ref $_[0] eq '' || ref($_[0]) =~ /^Math::/) {
226 1 50 33     5 if (@_ > 3 && $_[3] =~ /\d$/) {
227 0         0 $_begin = $_[0], $_end = $_[-1];
228 0         0 $_params->{$_pid}{sequence} = [ $_[0], $_[-1] ];
229             }
230             else {
231 1         2 $_begin = $_[0], $_end = $_[1];
232 1         3 $_params->{$_pid}{sequence} = [ @_ ];
233             }
234             }
235             else {
236 0         0 _croak("$_tag: (sequence) is not specified or valid");
237             }
238              
239 1 50       3 _croak("$_tag: (begin) is not specified for sequence")
240             unless (defined $_begin);
241 1 50       3 _croak("$_tag: (end) is not specified for sequence")
242             unless (defined $_end);
243              
244 1         2 $_params->{$_pid}{sequence_run} = undef;
245              
246 1         2 @_ = ();
247              
248 1         4 return run($_code);
249             }
250              
251             ###############################################################################
252             ## ----------------------------------------------------------------------------
253             ## Parallel map with MCE.
254             ##
255             ###############################################################################
256              
257             sub run (&@) {
258              
259 7 50 33 7 1 3209 shift if (defined $_[0] && $_[0] eq 'MCE::Map');
260              
261 7         10 my $_code = shift; $_total_chunks = 0; undef %_tmp;
  7         13  
  7         16  
262 7 100       26 my $_pkg = caller() eq 'MCE::Map' ? caller(1) : caller();
263 7         29 my $_pid = "$$.$_tid.$_pkg";
264              
265 7         13 my $_input_data; my $_max_workers = $_def->{$_pkg}{MAX_WORKERS};
  7         22  
266 7         16 my $_r = ref $_[0];
267              
268 7 100 66     38 if (@_ == 1 && $_r =~ /^(?:ARRAY|HASH|SCALAR|CODE|GLOB|FileHandle|IO::)/) {
269 1 50       5 _croak("$_tag: (HASH) not allowed as input by this MCE model")
270             if $_r eq 'HASH';
271 1         2 $_input_data = shift;
272             }
273              
274 7 50       26 if (defined (my $_p = $_params->{$_pid})) {
275             $_max_workers = MCE::_parse_max_workers($_p->{max_workers})
276 7 50       51 if (exists $_p->{max_workers});
277              
278 7 100 100     54 delete $_p->{sequence} if (defined $_input_data || scalar @_);
279 7 50       20 delete $_p->{user_func} if (exists $_p->{user_func});
280 7 50       19 delete $_p->{user_tasks} if (exists $_p->{user_tasks});
281 7 50       16 delete $_p->{use_slurpio} if (exists $_p->{use_slurpio});
282 7 50       18 delete $_p->{bounds_only} if (exists $_p->{bounds_only});
283 7 50       19 delete $_p->{gather} if (exists $_p->{gather});
284             }
285              
286 7         13 my $_chunk_size = do {
287 7   50     17 my $_p = $_params->{$_pid} || {};
288             (defined $_p->{init_relay} || defined $_def->{$_pkg}{INIT_RELAY}) ? 1 :
289             MCE::_parse_chunk_size(
290 7 50 33     93 $_def->{$_pkg}{CHUNK_SIZE}, $_max_workers, $_params->{$_pid},
291             $_input_data, scalar @_
292             );
293             };
294              
295 7 50       24 if (defined (my $_p = $_params->{$_pid})) {
296 7 100       16 if (exists $_p->{_file}) {
297 2         5 $_input_data = delete $_p->{_file};
298             } else {
299 5 50       11 $_input_data = $_p->{input_data} if exists $_p->{input_data};
300             }
301             }
302              
303             ## -------------------------------------------------------------------------
304              
305 7         38 MCE::_save_state($_MCE->{$_pid});
306              
307 7 100 66     42 if (!defined $_prev_c->{$_pid} || $_prev_c->{$_pid} != $_code) {
308 3 50       9 $_MCE->{$_pid}->shutdown() if (defined $_MCE->{$_pid});
309 3         6 $_prev_c->{$_pid} = $_code;
310              
311             my %_opts = (
312             max_workers => $_max_workers, task_name => $_tag,
313             user_func => sub {
314              
315 37     37   55 my ($_mce, $_chunk_ref, $_chunk_id) = @_;
316 37         66 my $_wantarray = $_mce->{user_args}[0];
317              
318 37 50       56 if ($_wantarray) {
319 37         106 my @_a;
320              
321 37 100       85 if (ref $_chunk_ref eq 'SCALAR') {
322 1 50       4 local $/ = $_mce->{RS} if defined $_mce->{RS};
323 1     1   89 open my $_MEM_FH, '<', $_chunk_ref;
  1         10  
  1         2  
  1         270  
324 1         2099 binmode $_MEM_FH, ':raw';
325 1         6 while (<$_MEM_FH>) { push @_a, &{ $_code }; }
  9         32  
  9         12  
326 1         7 close $_MEM_FH;
327 1         70 weaken $_MEM_FH;
328             }
329             else {
330 36 100       56 if (ref $_chunk_ref) {
331 27         28 push @_a, map { &{ $_code } } @{ $_chunk_ref };
  27         30  
  27         75  
  27         51  
332             } else {
333 9         17 push @_a, map { &{ $_code } } $_chunk_ref;
  9         8  
  9         67  
334             }
335             }
336              
337 37         394 MCE->gather($_chunk_id, \@_a);
338             }
339             else {
340 0         0 my $_cnt = 0;
341              
342 0 0       0 if (ref $_chunk_ref eq 'SCALAR') {
343 0 0       0 local $/ = $_mce->{RS} if defined $_mce->{RS};
344 0         0 open my $_MEM_FH, '<', $_chunk_ref;
345 0         0 binmode $_MEM_FH, ':raw';
346 0         0 while (<$_MEM_FH>) { $_cnt++; &{ $_code }; }
  0         0  
  0         0  
  0         0  
347 0         0 close $_MEM_FH;
348 0         0 weaken $_MEM_FH;
349             }
350             else {
351 0 0       0 if (ref $_chunk_ref) {
352 0         0 $_cnt += map { &{ $_code } } @{ $_chunk_ref };
  0         0  
  0         0  
  0         0  
353             } else {
354 0         0 $_cnt += map { &{ $_code } } $_chunk_ref;
  0         0  
  0         0  
355             }
356             }
357              
358 0 0       0 MCE->gather($_cnt) if defined $_wantarray;
359             }
360             },
361 3         30 );
362              
363 3 50       9 if (defined (my $_p = $_params->{$_pid})) {
364 3         3 for my $_k (keys %{ $_p }) {
  3         12  
365 3 50       9 next if ($_k eq 'sequence_run');
366 3 50       9 next if ($_k eq 'input_data');
367 3 50       12 next if ($_k eq 'chunk_size');
368              
369             _croak("$_tag: ($_k) is not a valid constructor argument")
370 3 50       9 unless (exists $MCE::_valid_fields_new{$_k});
371              
372 3         9 $_opts{$_k} = $_p->{$_k};
373             }
374             }
375              
376 3         9 for my $_k (qw/ tmp_dir freeze thaw init_relay use_threads /) {
377             $_opts{$_k} = $_def->{$_pkg}{uc($_k)}
378 15 50 33     36 if (exists $_def->{$_pkg}{uc($_k)} && !exists $_opts{$_k});
379             }
380              
381 3         21 $_MCE->{$_pid} = MCE->new(pkg => $_pkg, %_opts);
382             }
383              
384             ## -------------------------------------------------------------------------
385              
386 7         14 my $_cnt = 0; my $_wantarray = wantarray;
  7         14  
387              
388 7 100       31 $_MCE->{$_pid}{use_slurpio} = ($_chunk_size > &MCE::MAX_RECS_SIZE) ? 1 : 0;
389 7         20 $_MCE->{$_pid}{user_args} = [ $_wantarray ];
390              
391             $_MCE->{$_pid}{gather} = $_wantarray
392 7 50   0   26 ? \&_gather : sub { $_cnt += $_[0]; return; };
  0         0  
  0         0  
393              
394 7 100       20 if (defined $_input_data) {
    100          
395 3         7 @_ = ();
396 3         14 $_MCE->{$_pid}->process({ chunk_size => $_chunk_size }, $_input_data);
397 3         17 delete $_MCE->{$_pid}{input_data};
398             }
399             elsif (scalar @_) {
400 3         39 $_MCE->{$_pid}->process({ chunk_size => $_chunk_size }, \@_);
401 1         17 delete $_MCE->{$_pid}{input_data};
402             }
403             else {
404 1 50 33     6 if (defined $_params->{$_pid} && exists $_params->{$_pid}{sequence}) {
405             $_MCE->{$_pid}->run({
406             chunk_size => $_chunk_size,
407             sequence => $_params->{$_pid}{sequence}
408 1         9 }, 0);
409 1 50       7 if (exists $_params->{$_pid}{sequence_run}) {
410 1         3 delete $_params->{$_pid}{sequence_run};
411 1         2 delete $_params->{$_pid}{sequence};
412             }
413 1         3 delete $_MCE->{$_pid}{sequence};
414             }
415             }
416              
417 5         32 MCE::_restore_state();
418              
419 5 50       16 if ($_wantarray) {
    0          
420 5         74 return map { @{ $_ } } delete @_tmp{ 1 .. $_total_chunks };
  37         37  
  37         270  
421             }
422             elsif (defined $_wantarray) {
423 0         0 return $_cnt;
424             }
425              
426 0         0 return;
427             }
428              
429             ###############################################################################
430             ## ----------------------------------------------------------------------------
431             ## Private methods.
432             ##
433             ###############################################################################
434              
435             sub _croak {
436              
437 0     0   0 goto &MCE::_croak;
438             }
439              
440             1;
441              
442             __END__
443              
444             ###############################################################################
445             ## ----------------------------------------------------------------------------
446             ## Module usage.
447             ##
448             ###############################################################################
449              
450             =head1 NAME
451              
452             MCE::Map - Parallel map model similar to the native map function
453              
454             =head1 VERSION
455              
456             This document describes MCE::Map version 1.887
457              
458             =head1 SYNOPSIS
459              
460             ## Exports mce_map, mce_map_f, and mce_map_s
461             use MCE::Map;
462              
463             ## Array or array_ref
464             my @a = mce_map { $_ * $_ } 1..10000;
465             my @b = mce_map { $_ * $_ } \@list;
466              
467             ## Important; pass an array_ref for deeply input data
468             my @c = mce_map { $_->[1] *= 2; $_ } [ [ 0, 1 ], [ 0, 2 ], ... ];
469             my @d = mce_map { $_->[1] *= 2; $_ } \@deeply_list;
470              
471             ## File path, glob ref, IO::All::{ File, Pipe, STDIO } obj, or scalar ref
472             ## Workers read directly and not involve the manager process
473             my @e = mce_map_f { chomp; $_ } "/path/to/file"; # efficient
474              
475             ## Involves the manager process, therefore slower
476             my @f = mce_map_f { chomp; $_ } $file_handle;
477             my @g = mce_map_f { chomp; $_ } $io;
478             my @h = mce_map_f { chomp; $_ } \$scalar;
479              
480             ## Sequence of numbers (begin, end [, step, format])
481             my @i = mce_map_s { $_ * $_ } 1, 10000, 5;
482             my @j = mce_map_s { $_ * $_ } [ 1, 10000, 5 ];
483              
484             my @k = mce_map_s { $_ * $_ } {
485             begin => 1, end => 10000, step => 5, format => undef
486             };
487              
488             =head1 DESCRIPTION
489              
490             This module provides a parallel map implementation via Many-Core Engine.
491             MCE incurs a small overhead due to passing of data. A fast code block will
492             run faster natively. However, the overhead will likely diminish as the
493             complexity increases for the code.
494              
495             my @m1 = map { $_ * $_ } 1..1000000; ## 0.127 secs
496             my @m2 = mce_map { $_ * $_ } 1..1000000; ## 0.304 secs
497              
498             Chunking, enabled by default, greatly reduces the overhead behind the scene.
499             The time for mce_map below also includes the time for data exchanges between
500             the manager and worker processes. More parallelization will be seen when the
501             code incurs additional CPU time.
502              
503             sub calc {
504             sqrt $_ * sqrt $_ / 1.3 * 1.5 / 3.2 * 1.07
505             }
506              
507             my @m1 = map { calc } 1..1000000; ## 0.367 secs
508             my @m2 = mce_map { calc } 1..1000000; ## 0.365 secs
509              
510             Even faster is mce_map_s; useful when input data is a range of numbers.
511             Workers generate sequences mathematically among themselves without any
512             interaction from the manager process. Two arguments are required for
513             mce_map_s (begin, end). Step defaults to 1 if begin is smaller than end,
514             otherwise -1.
515              
516             my @m3 = mce_map_s { calc } 1, 1000000; ## 0.270 secs
517              
518             Although this document is about MCE::Map, the L<MCE::Stream> module can write
519             results immediately without waiting for all chunks to complete. This is made
520             possible by passing the reference to an array (in this case @m4 and @m5).
521              
522             use MCE::Stream;
523              
524             sub calc {
525             sqrt $_ * sqrt $_ / 1.3 * 1.5 / 3.2 * 1.07
526             }
527              
528             my @m4; mce_stream \@m4, sub { calc }, 1..1000000;
529              
530             ## Completes in 0.272 secs. This is amazing considering the
531             ## overhead for passing data between the manager and workers.
532              
533             my @m5; mce_stream_s \@m5, sub { calc }, 1, 1000000;
534              
535             ## Completed in 0.176 secs. Like with mce_map_s, specifying a
536             ## sequence specification turns out to be faster due to lesser
537             ## overhead for the manager process.
538              
539             =head1 OVERRIDING DEFAULTS
540              
541             The following list options which may be overridden when loading the module.
542              
543             use Sereal qw( encode_sereal decode_sereal );
544             use CBOR::XS qw( encode_cbor decode_cbor );
545             use JSON::XS qw( encode_json decode_json );
546              
547             use MCE::Map
548             max_workers => 4, # Default 'auto'
549             chunk_size => 100, # Default 'auto'
550             tmp_dir => "/path/to/app/tmp", # $MCE::Signal::tmp_dir
551             freeze => \&encode_sereal, # \&Storable::freeze
552             thaw => \&decode_sereal, # \&Storable::thaw
553             init_relay => 0, # Default undef; MCE 1.882+
554             use_threads => 0, # Default undef; MCE 1.882+
555             ;
556              
557             From MCE 1.8 onwards, Sereal 3.015+ is loaded automatically if available.
558             Specify C<< Sereal => 0 >> to use Storable instead.
559              
560             use MCE::Map Sereal => 0;
561              
562             =head1 CUSTOMIZING MCE
563              
564             =over 3
565              
566             =item MCE::Map->init ( options )
567              
568             =item MCE::Map::init { options }
569              
570             =back
571              
572             The init function accepts a hash of MCE options. The gather option, if
573             specified, is ignored due to being used internally by the module.
574              
575             use MCE::Map;
576              
577             MCE::Map->init(
578             chunk_size => 1, max_workers => 4,
579              
580             user_begin => sub {
581             print "## ", MCE->wid, " started\n";
582             },
583              
584             user_end => sub {
585             print "## ", MCE->wid, " completed\n";
586             }
587             );
588              
589             my @a = mce_map { $_ * $_ } 1..100;
590              
591             print "\n", "@a", "\n";
592              
593             -- Output
594              
595             ## 2 started
596             ## 1 started
597             ## 3 started
598             ## 4 started
599             ## 1 completed
600             ## 4 completed
601             ## 2 completed
602             ## 3 completed
603              
604             1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361
605             400 441 484 529 576 625 676 729 784 841 900 961 1024 1089 1156
606             1225 1296 1369 1444 1521 1600 1681 1764 1849 1936 2025 2116 2209
607             2304 2401 2500 2601 2704 2809 2916 3025 3136 3249 3364 3481 3600
608             3721 3844 3969 4096 4225 4356 4489 4624 4761 4900 5041 5184 5329
609             5476 5625 5776 5929 6084 6241 6400 6561 6724 6889 7056 7225 7396
610             7569 7744 7921 8100 8281 8464 8649 8836 9025 9216 9409 9604 9801
611             10000
612              
613             =head1 API DOCUMENTATION
614              
615             =over 3
616              
617             =item MCE::Map->run ( sub { code }, list )
618              
619             =item mce_map { code } list
620              
621             =back
622              
623             Input data may be defined using a list or an array reference. Unlike MCE::Loop,
624             Flow, and Step, specifying a hash reference as input data isn't allowed.
625              
626             ## Array or array_ref
627             my @a = mce_map { $_ * 2 } 1..1000;
628             my @b = mce_map { $_ * 2 } \@list;
629              
630             ## Important; pass an array_ref for deeply input data
631             my @c = mce_map { $_->[1] *= 2; $_ } [ [ 0, 1 ], [ 0, 2 ], ... ];
632             my @d = mce_map { $_->[1] *= 2; $_ } \@deeply_list;
633              
634             ## Not supported
635             my @z = mce_map { ... } \%hash;
636              
637             =over 3
638              
639             =item MCE::Map->run_file ( sub { code }, file )
640              
641             =item mce_map_f { code } file
642              
643             =back
644              
645             The fastest of these is the /path/to/file. Workers communicate the next offset
646             position among themselves with zero interaction by the manager process.
647              
648             C<IO::All> { File, Pipe, STDIO } is supported since MCE 1.845.
649              
650             my @c = mce_map_f { chomp; $_ . "\r\n" } "/path/to/file"; # faster
651             my @d = mce_map_f { chomp; $_ . "\r\n" } $file_handle;
652             my @e = mce_map_f { chomp; $_ . "\r\n" } $io; # IO::All
653             my @f = mce_map_f { chomp; $_ . "\r\n" } \$scalar;
654              
655             =over 3
656              
657             =item MCE::Map->run_seq ( sub { code }, $beg, $end [, $step, $fmt ] )
658              
659             =item mce_map_s { code } $beg, $end [, $step, $fmt ]
660              
661             =back
662              
663             Sequence may be defined as a list, an array reference, or a hash reference.
664             The functions require both begin and end values to run. Step and format are
665             optional. The format is passed to sprintf (% may be omitted below).
666              
667             my ($beg, $end, $step, $fmt) = (10, 20, 0.1, "%4.1f");
668              
669             my @f = mce_map_s { $_ } $beg, $end, $step, $fmt;
670             my @g = mce_map_s { $_ } [ $beg, $end, $step, $fmt ];
671              
672             my @h = mce_map_s { $_ } {
673             begin => $beg, end => $end,
674             step => $step, format => $fmt
675             };
676              
677             =over 3
678              
679             =item MCE::Map->run ( sub { code }, iterator )
680              
681             =item mce_map { code } iterator
682              
683             =back
684              
685             An iterator reference may be specified for input_data. Iterators are described
686             under section "SYNTAX for INPUT_DATA" at L<MCE::Core>.
687              
688             my @a = mce_map { $_ * 2 } make_iterator(10, 30, 2);
689              
690             =head1 MANUAL SHUTDOWN
691              
692             =over 3
693              
694             =item MCE::Map->finish
695              
696             =item MCE::Map::finish
697              
698             =back
699              
700             Workers remain persistent as much as possible after running. Shutdown occurs
701             automatically when the script terminates. Call finish when workers are no
702             longer needed.
703              
704             use MCE::Map;
705              
706             MCE::Map->init(
707             chunk_size => 20, max_workers => 'auto'
708             );
709              
710             my @a = mce_map { ... } 1..100;
711              
712             MCE::Map->finish;
713              
714             =head1 INDEX
715              
716             L<MCE|MCE>, L<MCE::Core>
717              
718             =head1 AUTHOR
719              
720             Mario E. Roy, S<E<lt>marioeroy AT gmail DOT comE<gt>>
721              
722             =cut
723