Description

Request that the loop stop execution as possible.

Break()

Request that loop stop execution of iterations beyond the current iteration as soon as possible.

IsExceptional

Return true if any iteration of the loop has thrown an exception.

IsStopped

Return true if any iteration has called Stop().

LowestBreakIteration

Return the index of the lowest iteration in which Break() was called.

ShouldExitCurrentIteration Return true if this iteration should exit.

The Stop() method is useful when you are looking for a specific result, as in the sequential loop where we looked for a word containing the letter k. When you call Stop(), the Parallel class doesn't stop any new iterations. However, iterations that are already running may continue to be performed, and as you saw earlier, Tasks are used to process more than one iteration value, so some of your data items may continue to be processed even after you have called Stop().

The Break() method is slightly different . If you call Break() in the tenth iteration, no further iterations will be started except those that are required to process the first to ninth items. Other iterations may be already running (including those that are processing later items) and will complete, which means that you are guaranteed to get at least the first ten items processed but may end up with more.

If Stop() and Break() seem a bit woolly, it is because the items in a parallel loop are not processed in sequence. This statement may seem obvious, but the trade-off inherent in a parallel loop is that the concurrent performance improvement comes at a cost of a lack of precision when you want to terminate the loop early. Listing 5-7 demonstrates a parallel loop that uses Stop(); this is the parallel implementation of looking for a word with the letter k.

Listing5-7. UsingStop() in a Parallel Loop using System;

using System.Collections.Generic; using System.Threading.Tasks;

namespace Listing_07 { class Program {

static void Main(string[] args) {

List<string> dataItems

= new List<string>() { "an", "apple", "a", "day", "keeps", "the", "doctor", "away" };

Parallel.ForEach(dataItems, (string item, ParallelLoopState state) => {

Console.WriteLine("Hit: {0}", item); state.Stop(); } else {

Console.WriteLine("Miss: {0}", item);

// wait for input before exiting Console.WriteLine("Press enter to finish"); Console.ReadLine();

Running Listing 5-7 produces the following result:

Miss: an Miss: day Miss: the Miss: apple Miss: doctor Miss: a Hit: keeps Miss: away

Press enter to finish

Notice that all of the items in the collection have been processed even through a match was found. This illustrates the slightly unpredictable nature of stopping a parallel loop. Listing 5-8 demonstrates a parallel loop that uses the Break() method, which is called when the square of the index is greater than 100.

Listing 5-8. Using BreakO in a Parallel Loop using System;

using System.Collections.Generic; using System.Threading.Tasks;

namespace Listing_08 {

class Listing_08 {

static void Main(string[] args) {

ParallelLoopResult res = Parallel.For(0, 100,

(int index, ParallelLoopState loopState) => {

// calculate the square of the index double sqr = Math.Pow(index, 2); // if the square value is > 100 then break if (sqr > 100) {

Console.WriteLine("Breaking on index {0}", index); loopState.Break(); } else {

// write out the value

Console.WriteLine("Square value of {0} is {l}", index, sqr);

// wait for input before exiting Console.WriteLine("Press enter to finish"); Console.ReadLine();

Running the listing produces the results that follow. See how the range of index values has been broken down so that Tasks can start processing at different points ? The values produced by squaring the index exceed our threshold, so those iterations terminated immediately.

Square value of 0 is 0 Breaking on index 25

Square

value

of

2

is

4

Square

value

of

3

is

9

Square

value

of

4

is

16

Square

value

of

5

is

25

Square

value

of

6

is

36

Square

value

of

7

is

49

Square

value

of

8

is

64

Square value of 9 is 81 Square value of 10 is 100 Breaking on index 11 Breaking on index 75 Square value of 1 is 1 Breaking on index 50 Press enter to finish

When, as in this example, Break() is called more than once, the Parallel class ensures that all of the items prior to the lowest index where Break() was called are processed. In Listing 5-8, Break() was called on indices 11, 25, 75, and 50. In this case, the lowest break occurred at index 11; therefore, all items prior to 11 will be processed.

The three ParallelLoopState properties IsStopped, LowestBreakIteration, and ShouldExitCurrentIteration allow you to improve the responsiveness of a parallel loop by checking the overall state of the loop from within your iteration. Checking these values, especially in iterations that will take a long time to complete, will reduce the amount of unwanted processing after Break() or Stop() has been called.

■ Tip See the "Getting Loop Results" section for details of how to determine if Break() or Stop() was called from outside of the Parallel.For() and Parallel.ForEach() methods.

0 0

Post a comment