15.01.2013 Views

Free-ebooks-library - Bahar Ali Khan

Free-ebooks-library - Bahar Ali Khan

Free-ebooks-library - Bahar Ali Khan

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

int[] numbers = { 1, 2, 3 };<br />

int sum = numbers.Aggregate (0, (total, n) => total + n); // 6<br />

We also saw in Chapter 9 that for unseeded aggregations, the supplied delegate must<br />

be associative and commutative. PLINQ will give incorrect results if this rule is violated,<br />

because it draws multiple seeds from the input sequence in order to aggregate<br />

several partitions of the sequence simultaneously.<br />

Explicitly seeded aggregations might seem like a safe option with PLINQ, but unfortunately<br />

these ordinarily execute sequentially because of the reliance on a single<br />

seed. To mitigate this, PLINQ provides another overload of Aggregate that lets you<br />

specify multiple seeds—or rather, a seed factory function. For each thread, it executes<br />

this function to generate a separate seed, which becomes a thread-local accumulator<br />

into which it locally aggregates elements.<br />

You must also supply a function to indicate how to combine the local and main<br />

accumulators. Finally, this Aggregate overload (somewhat gratuitously) expects a<br />

delegate to perform any final transformation on the result (you can achieve this as<br />

easily by running some function on the result yourself afterward). So, here are the<br />

four delegates, in the order they are passed:<br />

seedFactory<br />

Returns a new local accumulator<br />

updateAccumulatorFunc<br />

Aggregates an element into a local accumulator<br />

combineAccumulatorFunc<br />

Combines a local accumulator with the main accumulator<br />

resultSelector<br />

Applies any final transformation on the end result<br />

In simple scenarios, you can specify a seed value instead of a<br />

seed factory. This tactic fails when the seed is a reference type<br />

that you wish to mutate, because the same instance will then be<br />

shared by each thread.<br />

To give a very simple example, the following sums the values in a numbers array:<br />

numbers.AsParallel().Aggregate (<br />

() => 0, // seedFactory<br />

(localTotal, n) => localTotal + n, // updateAccumulatorFunc<br />

(mainTot, localTot) => mainTot + localTot, // combineAccumulatorFunc<br />

finalResult => finalResult) // resultSelector<br />

This example is contrived in that we could get the same answer just as efficiently<br />

using simpler approaches (such as an unseeded aggregate, or better, the Sum operator).<br />

To give a more realistic example, suppose we wanted to calculate the frequency<br />

of each letter in the English alphabet in a given string. A simple sequential solution<br />

might look like this:<br />

890 | Chapter 22: Parallel Programming

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!