Function std.parallelism.TaskPool.amap.amap
Eager parallel map. The eagerness of this function means it has less
overhead than the lazily evaluated TaskPool
and should be
preferred where the memory requirements of eagerness are acceptable.
functions
are the functions to be evaluated, passed as template
alias parameters in a style similar to
map
.
The first argument must be a random access range. For performance
reasons, amap will assume the range elements have not yet been
initialized. Elements will be overwritten without calling a destructor
nor doing an assignment. As such, the range must not contain meaningful
data: either un-initialized objects, or
objects in their
state.
auto amap(Args...)
(
Args args
)
if (isRandomAccessRange!(Args[0]));
auto numbers = iota(100_000_000.0);
// Find the square roots of numbers.
//
// Timings on an Athlon 64 X2 dual core machine:
//
// Parallel eager map: 0.802 s
// Equivalent serial implementation: 1.768 s
auto squareRoots = taskPool .amap!sqrt(numbers);
Immediately after the range argument, an optional work unit size argument
may be provided. Work units as used by amap
are identical to those
defined for parallel foreach. If no work unit size is provided, the
default work unit size is used.
// Same thing, but make work unit size 100.
auto squareRoots = taskPool .amap!sqrt(numbers, 100);
An output range for returning the results may be provided as the last argument. If one is not provided, an array of the proper type will be allocated on the garbage collected heap. If one is provided, it must be a random access range with assignable elements, must have reference semantics with respect to assignment to its elements, and must have the same length as the input range. Writing to adjacent elements from different threads must be safe.
// Same thing, but explicitly allocate an array
// to return the results in. The element type
// of the array may be either the exact type
// returned by functions or an implicit conversion
// target.
auto squareRoots = new float[numbers .length];
taskPool .amap!sqrt(numbers, squareRoots);
// Multiple functions, explicit output range, and
// explicit work unit size.
auto results = new Tuple!(float, real)[numbers .length];
taskPool .amap!(sqrt, log)(numbers, 100, results);
Note
A memory barrier is guaranteed to be executed after all results are written but before returning so that results produced by all threads are visible in the calling thread.
Tips
To perform the mapping operation in place, provide the same range for the input and output range.
To parallelize the copying of a range with expensive to evaluate elements
to an array, pass an identity function (a function that just returns
whatever argument is provided to it) to amap
.
Exception Handling:
When at least one exception is thrown from inside the map functions,
the submission of additional Task
objects is terminated as soon as
possible, in a non-deterministic manner. All currently executing or
enqueued work units are allowed to complete. Then, all exceptions that
were thrown from any work unit are chained using Throwable
and
rethrown. The order of the exception chaining is non-deterministic.