Cancelling a parallel loop

As we've seen in previous recipes, to create a task that can be cancelled, you pass in a cancellation token from a CancellationTokenSource object. If you then make a call to the CancellationTokenSource.Cancel method, the token signals all of the tasks that use it should terminate. The linked tasks detect this signal via the token and stop their activity in a safe manner.

Parallel loops support the same cancellation token mechanism as parallel tasks. In a parallel loop, you supply the CancellationToken to the method in the ParallelOptions parameter.

This recipe will download the contents of a book and split the words into a list of strings. We will then use a parallel loop to iterate through the words writing each to the console. However, we will create a separate task that sleeps for a few seconds and then calls the CancellationTokenSource.Cancel method which will cancel the loop.

How to do it…

Let's create a Console Application in Visual Studio so that we can see how to break a loop. The steps are as follows:

  1. Start a new project using the C# Console Application project template and assign BreakALoop as the Solution name.
  2. Add the following using directives to the top of your program class:
    using System;
    using System.Linq;
    using System.Net;
    using System.Threading;
    using System.Threading.Tasks;
  3. First, in the Main method of the program class, let's create a CancellationTokenSource and then add the CancellationToken to a ParallelOptions object.
    var tokenSource = new CancellationTokenSource();
    var options = new ParallelOptions
    {
        CancellationToken = tokenSource.Token
    };
  4. Next, just below the previous lines, create a simple task that sleeps for a few seconds and then calls the Cancel method on the CancellationTokenSource.
    Task.Factory.StartNew(() =>
    {
        Thread.Sleep(new TimeSpan(0,0,5));
        tokenSource.Cancel();
    });
  5. Now create a WebClient to download the text of a book, and split the words from the book into a list of strings.
    char[] delimiters = { ' ', ',', '.', ';', ':', '-', '_', '/', '"', '(', ')', 'u000A' };
    var client = new WebClient();
    const string headerText = "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)";
    client.Headers.Add("user-agent", headerText);
     var words = client.DownloadString(@"http://www.gutenberg.org/files/2009/2009.txt");
    var wordList = words.Split(delimiters, StringSplitOptions.RemoveEmptyEntries).Where(word => word.Length > 5).ToList();
    wordList.Sort();
  6. Finally, let's create a simple parallel foreach loop that writes the strings to the console. The loop should be in a try/catch and we should be catching OperationCancelledException and AggregateException.
    try
    {
        var loopResult = Parallel.ForEach(wordList, options, (currentWord, loopState) => Console.WriteLine(currentWord));
        Console.WriteLine("Loop Completed : {0}", loopResult.IsCompleted.ToString());
    }
    catch (OperationCanceledException)
    {
        Console.WriteLine("Operation Cancelled");
    }
    catch (AggregateException)
    {
        Console.WriteLine("Operation Cancelled");
    }
    Console.ReadLine();
  7. In Visual Studio 2012, press F5 to run the project. You should see output similar to the following screenshot:
    How to do it…

How it works…

In this recipe we are using another overload of the Parallel.ForEach method that accepts an IEnumerable source, a ParallelOptions object, and an Action delegate.

ForEach<TSource>(IEnumerable<TSource>, ParallelOptions, Action<TSource>)

The difference between cancelling a task and cancelling a parallel loop is how we pass in the CancellationToken. With a task, a CancellationToken is passed directly into the constructor of the task. For a parallel loop, we set the CancellationToken property of a ParallelOptions object with our CancellationToken, and then pass the ParallelOptions object into the parallel loop method.

If the token that signals the cancellation is the same token that is set on the ParallelOptions instance, then the parallel loop will throw an OperationCanceledException on cancellation. If a different token causes cancellation, the loop will throw an AggregateException with an OperationCanceledException as an InnerException. Both should be handled in your catch blocks.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.210.166