File Coverage

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