一起谈.NET技术,.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);
}

  我们来看下运行的结果:

  解释下上面的方法,并行循环的意图是将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);
}
}
}

  测试结果:

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

  总结

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

时间: 2024-09-15 09:29:19

一起谈.NET技术,.Net4.0 Parallel编程(三)Data Parallelism 下的相关文章

一起谈.NET技术,.Net4.0 Parallel编程(二)Data Parallelism 中

在上篇文章中看过了使用Parrallel.For.Parael.Foreach在效率上给我们带来的提高.本文就来如何终止循环.线程局部变量 进行说明. Thread-Local Variables 首先我们来看下线程局部变量,是的我们也许一直在想我们如何去定义一个线程局部变量呢.先看段顺序执行的代码: [TestMethod()]public void NormalSequenceTest(){int[] nums = Enumerable.Range(0, 1000000).ToArray()

.Net4.0 Parallel编程(二)Data Parallelism 中

在上篇文章中看过了使用Parrallel.For.Parael.Foreach在效率上给我们带来的提高.本文就来如何终止循环.线程局部变量 进行说明. Thread-Local Variables 首先我们来看下线程局部变量,是的我们也许一直在想我们如何去定义一个线程局部变量呢.先看段顺序执行的代码: [TestMethod()] public void NormalSequenceTest() { int[] nums = Enumerable.Range(0, 1000000).ToArra

一起谈.NET技术,.Net4.0 Parallel编程(一)Data Parallelism 上

Parallel.For 首先先写一个普通的循环: private void NormalFor(){for (var i = 0; i < 10000; i++) {for (var j = 0; j < 1000; j++) {for (var k = 0; k < 100; k++) { DoSomething(); } } }} 再看一个并行的For语句: private void ParallelFor(){ Parallel.For(0, 10000, i => {fo

一起谈.NET技术,.Net4.0 Parallel编程(四)Task 上

在之前的文章中,已经介绍过了Parallel Loop(上.中.下)的相关内容.本篇文章中会就Task基础部分进行些介绍. 初识Task 首先我们来构建一个简单的Task的Demo: static void Main(string[] args){ Task.Factory.StartNew(() => { Console.WriteLine("Hello word!"); }); Console.Read();} 在上面这段代码中我们构建出了一段非常简单的使用Task类的代码,

.Net4.0 Parallel编程(一)Data Parallelism 上

Parallel.For 首先先写一个普通的循环: private void NormalFor() { for (var i = 0; i < 10000; i++) { for (var j = 0; j < 1000; j++) { for (var k = 0; k < 100; k++) { DoSomething(); } } } } 再看一个并行的For语句: private void ParallelFor() { Parallel.For(0, 10000, i =&g

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

在上篇文章中介绍了如何Break.Stop循环,以及如何定义线程局部变量.在本文中介绍如何在外部去取消循环.以及异常的处理. Cancel 在并行的循环中支持通过传递ParallelOptions参数中的CancellationToken进行取消循环的控制,我们可以CancellationTokenSource实例化之后传递给ParallelOptions对象Cancellation值.下面来看个示例: [TestMethod] public void CancelLoop() { var so

.Net4.0 Parallel编程(四)Task 上

在之前的文章中,已经介绍过了Parallel Loop(上.中.下)的相关内容.本篇文章中会就Task基础部分进行些介绍. 初识Task 首先我们来构建一个简单的Task的Demo: static void Main(string[] args) { Task. Factory.StartNew(() => { Console.WriteLine("Hello word!"); }); Console.Read(); } 在上面这段代码中我们构建出了一段非常简单的使用Task类的

一起谈.NET技术,.Net 4.0 Parallel 编程(五)Task (中)

在上篇文章中我们看过了如何创建Task,本篇文章就各种类型Task的使用进行说明. Task Continuations 首先我们来看看延续的Task,所谓的延续的Task就是在第一个Task完成后自动启动下一个Task.我们通过ContinueWith方法来创建延续的Task.我们假设有一个接受xml解析的服务,首先从某个地方接受文件,然后解析入库,最后返回回执是否解析正确: [TestMethod]public void TaskParallelPrint() { var ReceiveTa

一起谈.NET技术,对抽象编程:接口和抽象类

1. 引言 在我之前的一篇post <抽象类和接口的谁是谁非 >中,和同事管伟的讨论,得到很多朋友的关注,因为是不成体系的论道,所以给大家了解造成不便,同时关于这个主题的系统性理论,我认为也有必要做以总结,因此才有了本篇的新鲜出炉.同时,我将把上贴中的问题顺便也在此做以交代. 2. 概念引入       什么是接口? 接口是包含一组虚方法的抽象类型,其中每一种方法都有其名称.参数和返回值.接口方法不能包含任何实现,CLR 允许接口可以包含事件.属性.索引器.静态方法.静态字段.静态构造函数以及