实现.NET 4.0下的Task类相似功能组件
实现 .NET 4.0 下的 Task 类相似功能:TaskExCum 组件详解
引言
随着 .NET 技术的发展,异步编程模型逐渐成为现代应用程序开发中的标准实践之一。.NET 4.5 引入了 Task 类,极大地简化了异步编程的过程。然而,许多遗留系统仍在使用 .NET 4.0 或更低版本,这些版本并未直接支持 Task 类的全部功能。为此,我们开发了 TaskExCum 组件,旨在为 .NET 4.0 提供与 .NET 4.5 相似的 Task 功能,包括 Task.Run() 和 Task.WhenAll() 方法。
组件概述
TaskExCum 是一个静态类,提供了以下主要功能:
- Run 方法:用于异步执行任务,并获取任务的结果。
- WhenAll 方法:用于等待多个任务完成,并收集所有任务的结果。
实现步骤
接下来,我们将详细讲解 TaskExCum 组件的实现步骤,以便读者能够更好地理解其工作原理,并将其应用于自己的项目中。
步骤 1: 创建 TaskExCum 类
首先,我们需要创建一个静态类 TaskExCum,并在其中定义静态方法。
public static class TaskExCum
{
// 方法定义将在后续步骤中添加
}
步骤 2: 实现 Run 方法
Run 方法允许开发者异步执行任务,并获取任务的结果。我们为 Run 方法提供了两种重载形式,分别用于执行无返回值的操作(Action)和有返回值的操作(Func<TResult>)。
public static Task<TResult> Run<TResult>(Func<TResult> function)
{
#if NET45
// 如果目标框架是 .NET 4.5 或更高版本,使用 Task.Run 方法
return Task.Run(function);
#else
// 如果目标框架是 .NET 4.0,使用 Task.Factory.StartNew 方法
return Task.Factory.StartNew(
function,
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Default
);
#endif
}
public static Task Run(Action action)
{
#if NET45
// 如果目标框架是 .NET 4.5 或更高版本,使用 Task.Run 方法
return Task.Run(action);
#else
// 如果目标框架是 .NET 4.0,使用 Task.Factory.StartNew 方法
return Task.Factory.StartNew(
action,
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Default
);
#endif
}
详细解释:
- 条件编译:使用
#if NET45编译符号,当项目目标框架为 .NET 4.5 及更高版本时,使用Task.Run方法。 - Task.Factory.StartNew:当项目目标框架为 .NET 4.0 时,使用
Task.Factory.StartNew方法来启动任务。- CancellationToken.None:表示没有取消令牌,任务不会被外部取消。
- TaskCreationOptions.None:表示没有特殊的任务创建选项。
- TaskScheduler.Default:这是关键点之一。
TaskScheduler.Default表示使用默认的线程池调度器,这意味着任务会在线程池中的一个线程上执行,而不是每次都启动一个新的线程。这有助于提高性能和资源利用率。
步骤 3: 实现 WhenAll 方法
WhenAll 方法用于等待多个任务完成,并收集所有任务的结果。我们为 WhenAll 方法提供了多种重载形式,以支持不同类型的任务集合。
public static Task<TResult[]> WhenAll<TResult>(IEnumerable<Task<TResult>> tasks)
{
#if NET45
// 如果目标框架是 .NET 4.5 或更高版本,使用 Task.WhenAll 方法
return Task.WhenAll(tasks);
#else
// 如果目标框架是 .NET 4.0,调用 WhenAllCore 方法
return WhenAllCore(tasks);
#endif
}
public static Task<TResult[]> WhenAll<TResult>(params Task<TResult>[] tasks)
{
#if NET45
// 如果目标框架是 .NET 4.5 或更高版本,使用 Task.WhenAll 方法
return Task.WhenAll(tasks);
#else
// 如果目标框架是 .NET 4.0,调用 WhenAllCore 方法
return WhenAllCore(tasks);
#endif
}
public static Task WhenAll(IEnumerable<Task> tasks)
{
#if NET45
// 如果目标框架是 .NET 4.5 或更高版本,使用 Task.WhenAll 方法
return Task.WhenAll(tasks);
#else
// 如果目标框架是 .NET 4.0,调用 WhenAllCore 方法
return WhenAllCore(tasks);
#endif
}
详细解释:
- 条件编译:使用
#if NET45编译符号,当项目目标框架为 .NET 4.5 及更高版本时,使用Task.WhenAll方法。 - WhenAllCore:当项目目标框架为 .NET 4.0 时,调用
WhenAllCore方法来实现相同的功能。
步骤 4: 实现 WhenAllCore 方法
WhenAllCore 方法是 WhenAll 方法的核心实现,负责处理任务集合,等待所有任务完成,并收集结果或异常信息。
private static Task WhenAllCore(IEnumerable<Task> tasks)
{
return WhenAllCore(tasks, (completedTasks, tcs) => tcs.TrySetResult(null));
}
private static Task<TResult[]> WhenAllCore<TResult>(IEnumerable<Task<TResult>> tasks)
{
return WhenAllCore(tasks.Cast<Task>(), (completedTasks, tcs) =>
{
tcs.TrySetResult(completedTasks.Select(t => ((Task<TResult>)t).Result).ToArray());
});
}
private static Task<TResult> WhenAllCore<TResult>(IEnumerable<Task> tasks, Action<Task[], TaskCompletionSource<TResult>> setResultAction)
{
if (tasks == null)
{
throw new ArgumentNullException("tasks");
}
Contract.EndContractBlock();
Contract.Assert(setResultAction != null);
var tcs = new TaskCompletionSource<TResult>();
var array = (tasks as Task[]) ?? tasks.ToArray();
if (array.Length == 0)
{
// 如果任务集合为空,直接设置结果
setResultAction(array, tcs);
}
else
{
Task.Factory.ContinueWhenAll(array, completedTasks =>
{
var exceptions = new List<Exception>();
bool hasCanceled = false;
foreach (var task in completedTasks)
{
if (task.IsFaulted)
{
// 收集所有失败任务的异常信息
exceptions.AddRange(task.Exception.InnerExceptions);
}
else if (task.IsCanceled)
{
// 检查是否有任务被取消
hasCanceled = true;
}
}
if (exceptions.Count > 0)
{
// 如果有异常,设置异常结果
tcs.TrySetException(exceptions);
}
else if (hasCanceled)
{
// 如果有任务被取消,设置取消结果
tcs.TrySetCanceled();
}
else
{
// 如果没有异常且没有任务被取消,设置成功结果
setResultAction(completedTasks, tcs);
}
}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
return tcs.Task;
}
详细解释:
- 参数验证:检查传入的任务集合是否为
null,如果是,则抛出ArgumentNullException。 - TaskCompletionSource:创建一个
TaskCompletionSource对象,用于管理任务的完成状态。 - 任务转换:将任务集合转换为数组,以便于后续处理。
- 任务数量检查:如果任务集合为空,直接调用
setResultAction设置结果。 - 等待所有任务完成:使用
Task.Factory.ContinueWhenAll方法等待所有任务完成。- 异常处理:遍历已完成的任务,收集所有失败任务的异常信息。
- 取消处理:检查是否有任务被取消。
- 设置结果:如果没有异常且没有任务被取消,调用
setResultAction设置结果。 - TaskScheduler.Default:这里再次使用
TaskScheduler.Default,确保任务在默认的线程池中执行,而不是每次都启动新的线程。
步骤 5: 添加异常处理逻辑
为了确保组件的健壮性,我们还需要在 WhenAllCore 方法中添加异常处理逻辑,确保所有异常都能被捕获并正确处理。
private static void AddPotentiallyUnwrappedExceptions(ref List<Exception> targetList, Exception exception)
{
var ex = exception as AggregateException;
Contract.Assert(exception != null);
Contract.Assert(ex == null || ex.InnerExceptions.Count > 0);
if (targetList == null)
{
targetList = new List<Exception>();
}
if (ex != null)
{
// 如果异常是 AggregateException,添加其内部异常
targetList.Add(ex.InnerExceptions.Count == 1 ? ex.InnerExceptions[0] : ex);
}
else
{
// 否则,直接添加异常
targetList.Add(exception);
}
}
详细解释:
- 异常类型检查:检查传入的异常是否为
AggregateException。 - 异常列表初始化:如果
targetList为null,则初始化一个新的列表。 - 异常添加:根据异常的类型,将异常或其内部异常添加到列表中。
示例代码
为了帮助读者更好地理解如何使用 TaskExCum 组件,下面是一些示例代码。
示例 1: 使用 Run 方法
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
try
{
// 异步执行任务并等待结果
string result = TaskExCum.Run(() => "Hello from Task!").Result;
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}
示例 2: 使用 WhenAll 方法
using System;
using System.Linq;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
try
{
// 创建多个任务
var tasks = Enumerable.Range(1, 5).Select(i => TaskExCum.Run(() => i * i)).ToArray();
// 等待所有任务完成并获取结果
int[] results = TaskExCum.WhenAll(tasks).Result;
// 输出结果
foreach (var result in results)
{
Console.WriteLine(result);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}
结论
通过 TaskExCum 组件,即使是在 .NET 4.0 这样的老框架版本中,我们也能够享受到现代异步编程模型带来的便利。希望这个组件能够帮助那些需要在旧版 .NET 框架中实现异步操作的开发者们,提高他们的开发效率和代码质量。如果你有任何建议或改进意见,欢迎留言交流!
https://i.cnblogs.com/posts/edit;postId=18515670
以上就是关于 TaskExCum 组件的详细介绍。希望通过这篇文章,读者能够更好地理解和使用这个组件,从而在自己的项目中实现高效的异步编程。如果有任何问题或需要进一步的帮助,请随时留言!
实现.NET 4.0下的Task类相似功能组件的更多相关文章
- C# 语言规范_版本5.0 (第10章 类)
1. 类 类是一种数据结构,它可以包含数据成员(常量和字段).函数成员(方法.属性.事件.索引器.运算符.实例构造函数.静态构造函数和析构函数)以及嵌套类型.类类型支持继承,继承是一种机制,它使派生类 ...
- .net core2.0下使用Identity改用dapper存储数据
前言. 已经好多天没写博客了,鉴于空闲无聊之时又兴起想写写博客,也当是给自己做个笔记.过了这么些天,我的文笔还是依然那么烂就请多多谅解了.今天主要是分享一下在使用.net core2.0下的实际遇到的 ...
- C#6.0语言规范(十) 类
类是可以包含数据成员(常量和字段),函数成员(方法,属性,事件,索引器,运算符,实例构造函数,析构函数和静态构造函数)和嵌套类型的数据结构.类类型支持继承,这是一种派生类可以扩展和专门化基类的机制. ...
- 在 .NET 4.0 下编写扩展代码以支持 async 异步编程
微软在C# 5中引入了async.await这两个异步编程的关键字,要使用这两个关键字需要你的IDE支持C#5.0语法,也就意味着你需要使用VS 2012版本以上IDE,或者在Vs2010卸载其编译器 ...
- Foundation框架下的常用类:NSNumber、NSDate、NSCalendar、NSDateFormatter、NSNull、NSKeyedArchiver
========================== Foundation框架下的常用类 ========================== 一.[NSNumber] [注]像int.float.c ...
- hdwiki model目录下的函数类
model目录下的函数类 actions.class.php(站内地图相关) getHTML:获得页面菜单和相关信息 getMap:生成站内地图 adv.class.php 对wiki_adve ...
- .NET Framework4.0 下的多线程
一.简介 在4.0之前,多线程只能用Thread或者ThreadPool,而4.0下提供了功能强大的Task处理方式,这样免去了程序员自己维护线程池,而且可以申请取消线程等...所以本文主要描述Tas ...
- Darwin Streaming server 的 Task 类
Darwin Streaming Server 是一个开放源代码的streaming server,对于streaming server的编程和软件结构有着一定的参考价值,它是使用C++写的,其中的并 ...
- Task类(任务)
任务表示应完成的某个单元的工作.这个单元的工作可以在单独的线程中运行,也可以以同步方式启动一个任务,这需要等待主调用线程.使用任务不仅可以获得一个抽象层,还可以对底层线程进行很多控制. 1.启动任务 ...
- 在VC6.0下如何调用Delphi5.0开发的进程内COM
因为本人的语言水平很差,考大学时150的总分,我考了个60分.外语也是,初中及格过一次,会考及格过一次.其它的时间好像从没有及格过.所以我不写文章,因我一百字的文章给我写,至少要出八九个错别字.哈哈… ...
随机推荐
- Deformable DETR:商汤提出可变型 DETR,提点又加速 | ICLR 2021 Oral
DETR能够消除物体检测中许多手工设计组件的需求,同时展示良好的性能.但由于注意力模块在处理图像特征图方面的限制,DETR存在收敛速度慢和特征分辨率有限的问题.为了缓解这些问题,论文提出了Deform ...
- FFmpeg开发笔记(四十八)从0开始搭建直播系统的开源软件架构
音视频技术的一个主要用途是直播,包括电视直播.电脑直播.手机直播等等,甚至在线课堂.在线问诊.安防监控等应用都属于直播系统的范畴.由于直播系统不仅涉及到音视频数据的编解码,还涉及到音视频数据的实时传 ...
- 代码随想录Day22
77. 组合 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合. 你可以按 任何顺序 返回答案. 示例 1: 输入:n = 4, k = 2 输出: [ [2,4], [ ...
- express请求数据的获取(get和post)body-parser
get请求 直接用res.query就可以拿到数据 post请求 需要使用中间件body-parser 第一步:安装body-parser npm i body-parser 第二步:按照模板进行使用 ...
- C# 读取excel数据到datatable
在项目中使用到遇到了需要将excel文件导入到数据库中,在此做个总结记录,防止后面人踩坑. 开发环境:VS2008+Win10 第一种方式:Office.Interop.Excel方式 数据量大时有 ...
- 【测试平台开发】——05Flask后端api开发实战(二)—— SqlAlchemy
SqlAlchemy SQLAlchemy是Python编程语言下的一款开源软件.提供了SQL工具包及对象关系映射(ORM)工具,使用MIT许可证发行. SQLAlchemy"采用简单的Py ...
- 阿里云 ACK Pod重启:pod was OOM killed
原因为:limits和requests的值设定为一样的了, pod request达到了limit限制,kubelet会统计到request+缓存就超限,然后触发自动重启 resources: lim ...
- WiFi基础(三):802.11ac/ax/be 与 WiFi4、WiFi5、WiFi6、WiFi7
liwen01 2024.09.08 前言 经过二十多年的发展,WiFi 在硬件能力.软件和算法.频谱资源.市场需求.电源与能效方面都有了很大的提升.所以我们能看到从最开始只有几 M 速率的 802. ...
- 阿里面试让聊一聊Redis 的内存淘汰(驱逐)策略
大家好,我是 V 哥,粉丝小A面试阿里,说被问到 Redis 的内存淘汰策略的问题,整理这个笔记给他参考,也分享给大家,如果你遇到这个问题,会怎么回答呢? Redis 的内存淘汰策略是指当Redis的 ...
- Android平台下的cpu利用率优化实现
目录 背景 CPU调频 概念 实现 验证 线程CPU亲和性 概念 亲和性控制 API 应用层控制实现 验证 线程优先级 概念 实现 验证 背景 为了进一步优化APP性能,最近针对如何提高应用对CPU的 ...