并行编程之任务并行

简介: 任务并行库 (TPL) 基于任务的概念。术语“任务并行”是指同时运行的一个或多个任务。任务表示异步操作,在某些方面它类似于创建新线程或 ThreadPool 工作项,但抽象级别较高。任务提供两个主要好处: 系统资源的使用效率更高,可伸缩性更好。

任务并行库 (TPL) 基于任务的概念。术语“任务并行”是指同时运行的一个或多个任务。任务表示异步操作,在某些方面它类似于创建新线程或 ThreadPool 工作项,但抽象级别较高。任务提供两个主要好处:

  • 系统资源的使用效率更高,可伸缩性更好。

    在后台,任务排队到 ThreadPool,ThreadPool 已使用登山等算法进行增强,这些算法能够确定并调整到可最大化吞吐量的线程数。这会使任务相对轻量,您可以创建很多任务以启用细化并行。为了补偿这一点,可使用众所周知的工作窃取算法提供负载平衡。

  • 对于线程或工作项,可以使用更多的编程控件。

    任务和围绕它们生成的框架提供了一组丰富的 API,这些 API 支持等待、取消、继续、可靠的异常处理、详细状态、自定义计划等功能。

出于这两个原因,在 .NET Framework 4 中,任务是用于编写多线程、异步和并行代码的首选 API。

 

1:隐式创建和运行任务

Parallel..::.Invoke 方法提供了一种简便方式,可同时运行任意数量的任意语句。只需为每个工作项传入 Action 委托即可。创建这些委托的最简单方式是使用 lambda 表达式。

Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());

为了更好地控制任务执行或从任务返回值,必须更加显式地使用 Task 对象。

 

2:显式创建和运行任务

任务由 System.Threading.Tasks..::.Task 类表示。返回值的任务由 System.Threading.Tasks..::.Task<(Of <(TResult>)>) 类表示,该类从 Task 继承。

任务对象处理基础结构详细信息,并提供可在任务的整个生存期内从调用线程访问的方法和属性。 例如,可以随时访问任务的 Status 属性,以确定它是已开始运行、已完成运行、已取消还是引发了异常。 状态由 TaskStatus 枚举表示。

在创建任务时,您赋予它一个用户委托,该委托封装该任务将执行的代码。该委托可以表示为命名的委托、匿名方法或 lambda 表达式。lambda 表达式可以包含对命名方法的调用,如下面的示例所示。

代码
 
    
Task < byte [] > getData = new Task < byte [] > (() => GetFileData());
Task
< double [] > analyzeData = getData.ContinueWith(x => Analyze(x.Result));
Task
< string > reportData = analyzeData.ContinueWith(y => Summarize(y.Result));
getData.Start();
// or...
Task < string > reportData2 = Task.Factory.StartNew(() => GetFileData())
.ContinueWith((x)
=> Analyze(x.Result))
.ContinueWith((y)
=> Summarize(y.Result));
System.IO.File.WriteAllText(
@" C:\reportFolder\report.txt " , reportData.Result);

 

使用 ContinueWhenAll()()() 方法和 ContinueWhenAny()()() 方法,可以从多个任务继续。有关更多信息,请参见延续任务如何:用延续将多个任务链接在一起

  
4:等待任务

System.Threading.Tasks..::.Task 类型和 System.Threading.Tasks..::.Task<(Of <(TResult>)>) 类型提供使您可以等待任务完成的 Wait 方法的一些重载。此外,静态 TaskWaitAll()()() 方法和 TaskWaitAny()()() 方法的重载使您可以等待任务数组的任一任务或所有任务完成。

通常,会出于以下某个原因等待任务:

  • 主线程依赖于任务计算的最终结果。

  • 您必须处理可能从任务引发的异常。

代码
 
   
private void buttonParallelTaskWait_Click( object sender, RoutedEventArgs e)
{
// Wait on a single task with no timeout specified.
Task task1 = Task.Factory.StartNew(() => DoSomeWork( 10000000 ));
task1.Wait();
ConsoleTexter.Clear();
ConsoleTexter.WriteLine(
" task1 has completed. " );

// Wait on a single task with a timeout specified.
Task task2 = Task.Factory.StartNew(() => DoSomeWork( 10000000 ));
task2.Wait(
100 ); // Wait for 100 ms.

if (task2.IsCompleted)
ConsoleTexter.WriteLine(
" task2 has completed. " );
else
ConsoleTexter.WriteLine(
" Timed out before task2 completed. " );

// Wait for all tasks to complete.
Task[] tasks = new Task[ 10 ];
for ( int i = 0 ; i < 10 ; i ++ )
{
tasks[i]
= Task.Factory.StartNew(() => DoSomeWork( 10000000 ));
}
Task.WaitAll(tasks);

// Wait for first task to complete.
Task < double > [] tasks2 = new Task < double > [ 3 ];

// Try three different approaches to the problem. Take the first one.
tasks2[ 0 ] = Task < double > .Factory.StartNew(() => TrySolution1());
tasks2[
1 ] = Task < double > .Factory.StartNew(() => TrySolution2());
tasks2[
2 ] = Task < double > .Factory.StartNew(() => TrySolution3());

int index = Task.WaitAny(tasks2);
double d = tasks2[index].Result;
ConsoleTexter.WriteLine(
" task[{0}] completed first with result of {1}. " , index, d);
MessageBox.Show(ConsoleTexter.Out.ToString());
}

 

5:任务中的异常处理

当某个任务引发一个或多个异常时,异常包装在 AggregateException 中。该异常传播回与该任务联接的线程,此线程通常是正在等待该任务或尝试访问该任务的 Result 属性的线程。此行为用于强制实施所有未处理的异常默认情况下应关闭进程的 .NET Framework 策略。调用代码可以通过在任务或任务组上使用 WaitWaitAll()()()WaitAny()()() 方法或 Result()()() 属性,或者通过在 try-catch 块中包括 Wait 方法,来处理异常。

联接线程也可以通过在对任务进行垃圾回收之前访问 Exception 属性来处理异常。通过访问此属性,可防止未处理的异常触发在对象完成时关闭进程的异常传播行为。

异常处理的例子见下文的取消任务。 

 

6:取消任务

System.Threading.Tasks..::.TaskSystem.Threading.Tasks..::.Task<(Of <(TResult>)>) 类支持通过使用取消标记(.NET Framework 4 中的新功能)进行取消。有关更多信息,请参见取消在任务的类中,取消涉及到表示可取消操作的用户委托与请求取消的代码之间的协作。 成功的取消涉及到调用 CancellationTokenSource..::.Cancel 方法的请求代码,以及及时终止操作的用户委托。可以使用以下选项之一终止操作:

  • 简单地从委托中返回。在许多情况下,这样已足够;但是,采用这种方式“取消”的任务实例会转换为 RanToCompletion 状态,而不是 Canceled 状态。

  • 引发 OperationCanceledException,并将其传递到在其上请求了取消的标记。完成此操作的首选方式是使用 ThrowIfCancellationRequested 方法。采用这种方式取消的任务会转换为 Canceled 状态,调用代码可使用该状态来验证任务是否响应了其取消请求。

 

代码
 
    
CancellationTokenSource tokenSource2;
CancellationToken ct;
Task task;
public UserControlParallel()
{
InitializeComponent();
tokenSource2
= new CancellationTokenSource();
ct
= tokenSource2.Token;
}

// 任务开始
private void buttonParallelTaskStart_Click( object sender, RoutedEventArgs e)
{
task
= Task.Factory.StartNew(() =>
{
// Were we already canceled?
ct.ThrowIfCancellationRequested();
bool moreToDo = true ;
while (moreToDo)
{
// Poll on this property if you have to do
// other cleanup before throwing.
Thread.Sleep( 100 );
if (ct.IsCancellationRequested)
{
// Clean up here, then...
ct.ThrowIfCancellationRequested();
}
}
}, tokenSource2.Token);
// Pass same token to StartNew.
}

// 任务结束
private void buttonParallelTaskCancel_Click( object sender, RoutedEventArgs e)
{
tokenSource2.Cancel();
// Just continue on this thread, or Wait/WaitAll with try-catch:
try
{
task.Wait();
}
catch (AggregateException err)
{
ConsoleTexter.Clear();
foreach (var v in err.InnerExceptions)
ConsoleTexter.WriteLine(
" msg: " + v.Message);
MessageBox.Show(ConsoleTexter.Out.ToString());
}
}

更多参考http://msdn.microsoft.com/zh-cn/library/dd537609.aspx

 

 

 
Creative Commons License本文基于 Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 http://www.cnblogs.com/luminji(包含链接)。如您有任何疑问或者授权方面的协商,请给我留言。
目录
相关文章
|
XML 前端开发 Java
Android App开发图像加工中卡片视图CardView和给图像添加装饰的讲解以及实战(附源码 简单易懂)
Android App开发图像加工中卡片视图CardView和给图像添加装饰的讲解以及实战(附源码 简单易懂)
709 0
|
机器学习/深度学习 算法 计算机视觉
使用sklearn进行特征选择
背景 一个典型的机器学习任务,是通过样本的特征来预测样本所对应的值。如果样本的特征少,我们会考虑增加特征。而现实中的情况往往是特征太多了,需要减少一些特征。
|
11月前
|
机器学习/深度学习 人工智能 算法
基于AI的性能优化技术研究
基于AI的性能优化技术研究
|
算法 计算机视觉
非极大值抑制详细原理(NMS含代码及详细注释)
非极大值抑制(Non-Maximum Suppression,NMS)详细原理(含代码及详细注释)
2372 1
非极大值抑制详细原理(NMS含代码及详细注释)
|
机器学习/深度学习 自动驾驶 算法
ONNX 在自动驾驶汽车中的应用案例
【8月更文第27天】随着自动驾驶技术的快速发展,高效的模型部署和跨平台的支持变得尤为重要。Open Neural Network Exchange (ONNX) 作为一种开放的模型格式,可以促进不同深度学习框架之间的模型转换,同时支持多种硬件平台上的高效执行。本文将探讨 ONNX 在自动驾驶系统中的应用,特别是如何在感知、决策和控制等核心环节中发挥作用。
669 3
|
消息中间件 人工智能 Kafka
Apache Kafka + 向量数据库 + LLM = 实时 GenAI
生成式AI(GenAI)革新了企业架构,催生新数据集成模式与最佳实践。借助Apache Kafka与Apache Flink,企业能高效处理大规模实时数据,连接各类数据库与分析平台。Kafka作为核心组件,支持GenAI应用如服务台自动化、聊天机器人及内容审核。结合大型语言模型(LLM)、检索增强生成(RAG)与向量数据库,Kafka与Flink共同打造强大数据流处理能力,克服GenAI挑战,如昂贵训练成本、数据时效性与准确性。通过语义搜索与RAG设计模式,确保LLM生成内容可靠无误。
457 0
|
弹性计算 Linux 编译器
CoreBolt——在倚天上基于 Coresight 做 BOLT 优化
CoreBolt 是一种倚天平台的性能优化解决方案。CoreBolt 通过 Coresight 在程序运行时采集程序运行信息,对程序的热代码和冷代码进行区分,并通过 BOLT 对程序进行代码段重排,从而提升程序代码的局部性,减少程序运行过程中由 CPU iCache miss 和 iTLB miss 引发的性能下降,提升程序的整体性能。
1487 6
|
开发者 Windows
什么是DRM以及为何需要移除它?
数字版权管理(DRM)是一种用于保护数字内容的技术,它限制了用户对特定内容的使用和传播。DRM技术的目的是在保护知识产权的同时,防止非法复制和盗版。然而,有些人认为DRM限制了用户的合法权益,因此需要将其移除。
2806 1
看看FIQ和IRQ
看看FIQ和IRQ
409 0
|
机器学习/深度学习 人工智能 编解码
关键点检测从入门到进阶
关键点检测,也被称作关键点定位或关键点对齐(keypoint alignment),在不同的任务中名字可能略有差异。比如,在人脸关键点定位中会被称作facemark alignment,在人体关键点检测中称作pose alignment。