博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
并行编程之任务并行
阅读量:7192 次
发布时间:2019-06-29

本文共 4730 字,大约阅读时间需要 15 分钟。

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

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

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

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

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

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

 

1:隐式创建和运行任务

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

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

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

 

2:显式创建和运行任务

任务由  类表示。返回值的任务由  类表示,该类从  继承。

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

在创建任务时,您赋予它一个用户委托,该委托封装该任务将执行的代码。该委托可以表示为命名的委托、匿名方法或 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:等待任务

 类型和  类型提供使您可以等待任务完成的 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 策略。调用代码可以通过在任务或任务组上使用 、WaitAll()()() 或 WaitAny()()() 方法或 Result()()() 属性,或者通过在 try-catch 块中包括 Wait 方法,来处理异常。

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

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

 

6:取消任务

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

  • 简单地从委托中返回。在许多情况下,这样已足够;但是,采用这种方式“取消”的任务实例会转换为 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://naxkm.baihongyu.com/

你可能感兴趣的文章
springMVC中不通过注解方式获取指定Service的javabean
查看>>
Kruskal算法(求最小生成树)
查看>>
JavaScript-事件周期-点击替换颜色
查看>>
c# 遍历文件夹及其所有文件
查看>>
电商2.0时代
查看>>
关于 Android 程序员最近的状况
查看>>
虚拟化之lxc
查看>>
Java 包装类 自动装箱和拆箱
查看>>
利用ExpandableListView和gridview 显示可展开折叠菜单导航
查看>>
再看tp
查看>>
SQL Server 2012 还原选项的变化
查看>>
细节之处方显linux真功夫
查看>>
谈谈SQL Server高可用的常见问题
查看>>
Provisioning Services 7.8 入门系列教程之六 手动添加设备
查看>>
技术大牛对程序员招聘的吐槽和建议
查看>>
《未来架构师》的教学范例(2)
查看>>
Exchange 混合部署—Exchange 2007到Exchange 2013迁移
查看>>
C++构造函数和析构函数的学习(一)
查看>>
Redhat更新yum源
查看>>
jmeter企业内训简报
查看>>