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

简介: 我们常常会遇到需要利用并行处理,尽量发挥多核或多CPU的潜能,提高程序运行效率的场景。在.NET环境下,常用的做法是使用Thread,多线程方式进行并行处理。但在.Net4.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框架底层实现可能大致相同。但多任务的代码写法更为简洁,也更为灵活。

 

二、利用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、执行结果截图

 

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

实现的关键代码:

// 声明并获取一个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,回到当前调用的方法中。




 

目录
相关文章
|
2月前
使用的是.NET Framework 4.0,并且需要使用SMTP协议发送电子邮件
使用的是.NET Framework 4.0,并且需要使用SMTP协议发送电子邮件
56 1
|
2月前
|
开发框架 缓存 监控
NET Framework 到 .NET 5/6 的迁移是重大的升级
本文详细介绍了从 .NET Framework 4.8 迁移到 .NET 5/6 的过程,通过具体案例分析了迁移策略与最佳实践,包括技术栈评估、代码迁移、依赖项更新及数据库访问层的调整,强调了分阶段迁移、保持代码可维护性及性能监控的重要性。
61 3
|
2月前
|
机器学习/深度学习 编解码 算法
【小样本图像分割-4】nnU-Net: Self-adapting Framework for U-Net-Based Medical Image Segmentation
《nnU-Net: 自适应框架用于基于U-Net的医学图像分割》是一篇2018年的论文,发表在Nature上。该研究提出了一种自适应的医学图像分割框架nnU-Net,能够自动调整模型的超参数以适应不同的数据集。通过2D和3D U-Net及级联U-Net的组合,nnU-Net在10个医学分割数据集上取得了卓越的性能,无需手动调整。该方法强调数据增强、预处理和训练策略等技巧,为医学图像分割提供了一个强大的解决方案。
93 0
【小样本图像分割-4】nnU-Net: Self-adapting Framework for U-Net-Based Medical Image Segmentation
|
2月前
.NET 4.0下实现.NET4.5的Task类相似功能组件
【10月更文挑战第29天】在.NET 4.0 环境下,可以使用 `BackgroundWorker` 类来实现类似于 .NET 4.5 中 `Task` 类的功能。`BackgroundWorker` 允许在后台执行耗时操作,同时不会阻塞用户界面线程,并支持进度报告和取消操作。尽管它有一些局限性,如复杂的事件处理模型和不灵活的任务管理方式,但在某些情况下仍能有效替代 `Task` 类。
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
本文讨论了在基于.NET 6和.NET Framework的WinForms项目中添加图表控件的不同方法。由于.NET 6的WinForms项目默认不包含Chart控件,可以通过NuGet包管理器安装如ScottPlot等图表插件。而对于基于.NET Framework的WinForms项目,Chart控件是默认存在的,也可以通过NuGet安装额外的图表插件,例如LiveCharts。文中提供了通过NuGet添加图表控件的步骤和截图说明。
winform .net6 和 framework 的图表控件,为啥项目中不存在chart控件,该如何解决?
|
4月前
|
开发框架 缓存 前端开发
实战.NET Framework 迁移到 .NET 5/6
从.NET Framework 迁移到.NET 5/6 是一次重要的技术革新,涵盖开发环境与应用架构的全面升级。本文通过具体案例详细解析迁移流程,包括评估现有应用、利用.NET Portability Analyzer 工具识别可移植代码、创建新项目、逐步迁移代码及处理依赖项更新等关键步骤。特别关注命名空间调整、JSON 序列化工具更换及数据库访问层重构等内容,旨在帮助开发者掌握最佳实践,确保迁移过程平稳高效,同时提升应用性能与可维护性。
151 2
|
4月前
|
开发框架 JSON 监控
实战指南:从 .NET Framework 迁移到 .NET 5/6 的策略与最佳实践
【8月更文挑战第28天】从 .NET Framework 迁移到 .NET 5/6 是一次重要的技术升级,涉及开发环境与应用架构的改进。本文通过具体案例分析,介绍迁移策略与最佳实践,帮助开发者顺利完成转变。
94 1
|
3月前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
48 7
|
3月前
|
存储 开发框架 前端开发
ASP.NET MVC 迅速集成 SignalR
ASP.NET MVC 迅速集成 SignalR
75 0
|
4月前
|
开发框架 前端开发 .NET
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
56 0