• .Net4.0 Parallel编程(三)Data Parallelism下


    上篇文章中介绍了如何Break、Stop循环,以及如何定义线程局部变量。在本文中介绍如何在外部去取消循环、以及异常的处理。

    Cancel

    在并行的循环中支持通过传递ParallelOptions参数中的CancellationToken进行取消循环的控制,我们可以CancellationTokenSource实例化之后传递给ParallelOptions对象Cancellation值。下面来看个示例:

            [TestMethod]
            public void CancelLoop()
            {
                var sourceNums = Enumerable.Range(0, 1000000000);
                var cts = new CancellationTokenSource();
                var po = new ParallelOptions();
                var stack = new ConcurrentStack<int>();
                po.CancellationToken = cts.Token;
                po.MaxDegreeOfParallelism = System.Environment.ProcessorCount;
                Task.Factory.StartNew(() =>
                {
                    foreach (var num in sourceNums)
                    {
                        if (num == 1000000)
                            cts.Cancel();
                    }
                });
    
                try
                {
                    Parallel.ForEach(sourceNums,po, num => 
                    {
                        stack.Push(num);
                        po.CancellationToken.ThrowIfCancellationRequested();
                    });
                }
                catch (OperationCanceledException e)
                {
                    Console.WriteLine(e.Message);
                }
                Console.WriteLine(stack.Count);
            }

    我们来看下运行的结果:

    image

    解释下上面的方法,并行循环的意图是将sourceNums里面的元素推到Stack中,然后另外开启了一个线程来控制了什么时候进行cancel操作。也许会有个疑问,为什么不是1000000呢,原因很简单就是上面的控制的线程不可能跟下面的同时开始的,而其每次迭代运行所需要的时间也是不同的。

    上面的示例中我们看的是如何终止Parallel的ForEach循环,终止For循环是一样的,For方法中也提供了ParallelOptions参数。

    Handel Exceptions

    在处理并行循环的异常的与顺序循环异常的处理是有所不同的,并行循环里面可能会一个异常在多个循环中出现,或则一个线程上的异常导致另外一个线程上也出现异常。比较好的处理方式就是,首先获取所有的异常最后通过AggregateException来包装所有的循环的异常,循环结束后进行throw。看一段示例代码:

            private void HandleNumbers(int[] numbers)
            {
                var exceptions = new ConcurrentQueue<Exception>();
                Parallel.For(0, numbers.Length, i => 
                {
                    try
                    {
                        if (numbers[i] > 10 && numbers[i] < 20)
                        {
                            throw new Exception(String.Format("numbers[{0}] betwewn 10 to 20",i));
                        }
                    }
                    catch (Exception e)
                    {
                        exceptions.Enqueue(e);
                    }
                });
                if (exceptions.Count > 0)
                    throw new AggregateException(exceptions);
    
            }
    测试方法:
            [TestMethod()]
            public void HandleExceptions()
            {
                var numbers = Enumerable.Range(0, 10000).ToArray();
                try
                {
                    this.HandleNumbers(numbers);
                }
                catch(AggregateException exceptions)
                {
                    foreach (var ex in exceptions.InnerExceptions)
                    {
                        Console.WriteLine(ex.Message);
                    }
                }
            }

    测试结果:

    image

    对上面的方法说明下,在HandleNumbers方法中,就是一个小的demo如果元素的值出现在10-20之间就抛出异常。在上面我们的处理方法就是:在循环时通过队列将所有的异常都集中起来,循环结束后来抛出一个AggregateException。

    总结

    在本文中主要说明了如何处理异常以及如何在外部取消一个并行循环。到此Task  Parallel Library中的数据并行部分已经结束。下面的会就学习下,任务并行部分。

    作者:Henllyee Cui
    出处: http://henllyee.cnblogs.com/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明。
  • 相关阅读:
    前端攻城狮学习笔记九:让你彻底弄清offset
    JavaScript中Element与Node的区别,children与childNodes的区别
    JavaScript代码优化实战之一:缓存变量,关键字过滤
    【转】纯CSS画的基本图形(矩形、圆形、三角形、多边形、爱心、八卦等),NB么
    包装对象——JavaScript中原始类型拥有属性的原因
    关于两个容积不同的瓶子中装水可以得到哪些精确值的问题的算法
    JavaScript中判断鼠标按键(event.button)
    累了休息一会儿吧——分享一个JavaScript版扫雷游戏
    用CSS让未知高度内容垂直方向居中
    空间换时间,把递归的时间复杂度降低到O(2n)
  • 原文地址:https://www.cnblogs.com/Henllyee/p/ParallelProgaramming3.html
Copyright © 2020-2023  润新知