.Net Framework 4.0 中利用Task实现并行处理、串并行混合处理

    我们常常会遇到需要利用并行处理,尽量发挥多核或多CPU的潜能,提高程序运行效率的场景。在.NET环境下,常用的做法是使用Thread,多线程方式进行并行处理。但在.Net4.0中,微软提供一种新的概念——Task(任务),换句话说,并行处理由“多线程”进化为了“多任务”的方式。

 

一、利用Task实现多任务处理

测试1:

以下为测试过程,模拟多次调用一耗时方法,分别使用串行、多线程方式、多任务方式:

1、建立一虚拟耗时的方法

        /// <summary>
/// 模拟执行耗时的方法
/// </summary>
public static void TestLongTimeMethod()
{
Console.WriteLine("method start:" + System.DateTime.Now.ToString());
System.Threading.Thread.Sleep(5000);
Console.WriteLine("method end:" + System.DateTime.Now.ToString());
}

 

2、传统串行调用方式、多线程调用、多任务调用

        #region 传统串行方式
/// <summary>
/// 传统串行方式
/// </summary>
public static void lineMethod()
{
TestLongTimeMethod();
TestLongTimeMethod();
TestLongTimeMethod();
}
#endregion
        #region 多线程方式
/// <summary>
/// 多线程方式
/// </summary>
public static void threadMethod()
{
var thread1 = new Thread(() => TestLongTimeMethod());
var thread2 = new Thread(() => TestLongTimeMethod());
thread1.Start();
thread2.Start();
TestLongTimeMethod();
thread1.Join();
thread2.Join();
}
#endregion
        #region 多任务方式
/// <summary>
/// 多任务方式——线程池中,委托给CPU,全部执行完后再跳出线程池
/// </summary>
public static void taskMethod()
{
// 方式1:使用Parallel.Invoke,可同时并行多个任务,任务调用的方法可以不同
//Parallel.Invoke(
// () => TestLongTimeMethod(),
// () => TestLongTimeMethod(),
// () => TestLongTimeMethod()
//);

// 方式2:使用Parallel.For,可设定并行多个任务,任务调用的方法相同
int times = 3;
Parallel.For(
0,
times,
i => TestLongTimeMethod()
);
}
#endregion

3、模拟执行过程,统计过程用时

static void Main(string[] args)
{
int maxTimes = 1;
DateTime ds = new DateTime();
DateTime de = new DateTime();
DateTime ds1 = new DateTime();
DateTime de1 = new DateTime();
DateTime ds2 = new DateTime();
DateTime de2 = new DateTime();

#region lineMethod 串行

Console.WriteLine("**************【串 行】**************");
ds = DateTime.Now;
Console.WriteLine("**************[StartTime:" + ds.ToString() + "]**************");
for (int intLoop = 0; intLoop < maxTimes; intLoop++)
{
Console.WriteLine("**************[" + (intLoop + 1).ToString() + "]**************");
lineMethod();
}
de = DateTime.Now;
Console.WriteLine("**************[EndTime:" + de.ToString() + "]**************");
System.Threading.Thread.Sleep(500);

#endregion

#region threadMethod 多线程

Console.WriteLine("**************【多线程】**************");
ds1 = DateTime.Now;
Console.WriteLine("**************[StartTime:" + ds1.ToString() + "]**************");
for (int intLoop = 0; intLoop < maxTimes; intLoop++)
{
Console.WriteLine("**************[" + (intLoop + 1).ToString() + "]**************");
threadMethod();
}
de1 = DateTime.Now;
Console.WriteLine("**************[EndTime:" + de1.ToString() + "]**************");
System.Threading.Thread.Sleep(500);

#endregion

#region taskMethod 多任务

Console.WriteLine("**************【多任务】**************");
ds2 = DateTime.Now;
Console.WriteLine("**************[StartTime:" + ds2.ToString() + "]**************");
for (int intLoop = 0; intLoop < maxTimes; intLoop++)
{
Console.WriteLine("**************[" + (intLoop + 1).ToString() + "]**************");
taskMethod();
}
de2 = DateTime.Now;
Console.WriteLine("**************[EndTime:" + de2.ToString() + "]**************");
System.Threading.Thread.Sleep(500);

#endregion

Console.WriteLine("lineMethod 【串 行】 : " + (de - ds).TotalMilliseconds.ToString());
Console.WriteLine("threadMethod【多线程】 : " + (de1 - ds1).TotalMilliseconds.ToString());
Console.WriteLine("taskMethod 【多任务】 : " + (de2 - ds2).TotalMilliseconds.ToString());


Console.ReadLine();
}

4、执行结果截图

.Net Framework 4.0 中利用Task实现并行处理、串并行混合处理

 

结论:从结果可以看出多线程或多任务的性能明显高于串行方式。多线程或多任务执行效率区别不大,.NET框架底层实现可能大致相同。但多任务的代码写法更为简洁,也更为灵活。

 

二、利用Task实现并行、串行的执行顺序定义

测试2::

1、假定A、B、C、D、E 多任务的执行顺序为:A、B 执行后,执行C,A 执行后,执行 D, B 执行后,执行 E
执行时的测试方法如下(即执行时显示执行的名称,并按传入的时间参数,决定进程休眠的时间):

    public class TestAction
{
private int _p;
private string _actionName;

public TestAction(string actionName, int p)
{
_actionName = actionName;
_p = p;
}

public void Do()
{
Console.WriteLine(System.DateTime.Now.ToString() + " | 开始执行" + _actionName);
Thread.Sleep(new TimeSpan(0, 0, _p));
Console.WriteLine(System.DateTime.Now.ToString() + " | 执行完毕" + _actionName);
}
}

2、测试方法(传统串行、串并行结合)

     假定各任务分别耗时为A(5秒)、B(5秒)、C(2秒)、D(1秒)、E(2秒)。则串行需用时5+5+2+1+2=15 秒,串并行结合(A、B -> C,A -> D,B -> E) 需用时 5+2 = 7 秒.

测试程序如下:

        /// <summary>
/// 按设计的顺序测试(同时考虑串行与并行): A、B -> C,A -> D,B -> E
/// </summary>
public static void SortTaskMethod()
{
Console.WriteLine("--------------[串行]--------------");
(new TestAction("A", 5)).Do();
(new TestAction("B", 5)).Do();
(new TestAction("C", 2)).Do();
(new TestAction("D", 1)).Do();
(new TestAction("E", 2)).Do();

Console.WriteLine("--------------[多任务]--------------");
TaskFactory factory = new TaskFactory();
Task a = factory.StartNew((new TestAction("A", 5)).Do);
Task b = factory.StartNew((new TestAction("B", 5)).Do);
Task c = factory.ContinueWhenAll(new Task[] { a, b }, ((preTasks) => (new TestAction("C", 2)).Do()));
Task d = factory.ContinueWhenAll(new Task[] { a }, ((preTasks) => (new TestAction("D", 1)).Do()));
Task e = factory.ContinueWhenAll(new Task[] { b }, ((preTasks) => (new TestAction("E", 2)).Do()));
}

3、执行结果截图

.Net Framework 4.0 中利用Task实现并行处理、串并行混合处理

 

结论:与测试预想结果一致

实现的关键代码:

// 声明并获取一个Task工厂实例

TaskFactory factory = new TaskFactory();

// 利用工厂创建一个任务,并执行指定的方法

Task a = factory.StartNew((new TestAction("A", 5)).Do);

// 利用工厂创建后续任务(根据前置任务),并执行指定的方法

Task c = factory.ContinueWhenAll(new Task[] { a, b }, ((preTasks) => (new TestAction("C", 2)).Do()));


请注意以上使用工厂方式获得的任务实例,与之前介绍的Parallel.Invoke 方式,二者有很重要的区别:工厂方式获取任务实例后即分配给系统委托,不受当前调用的方法约束;但invoke方式,括号内部声明的多个任务,必须全部执行结束,才会跳出invoke,回到当前调用的方法中。




 

上一篇:再见,齐达内,再见,法国队


下一篇:ASP.NET MVC5+EF6+EasyUI 后台管理系统(61)-如何使用框架来开发