引言
随着 .NET 技术的发展,异步编程模型逐渐成为现代应用程序开发中的标准实践之一。.NET 4.5 引入了 Task
类,极大地简化了异步编程的过程。然而,许多遗留系统仍在使用 .NET 4.0 或更低版本,这些版本并未直接支持 Task
类的全部功能。为此,我们开发了 TaskExCum
组件,旨在为 .NET 4.0 提供与 .NET 4.5 相似的 Task
功能,包括 Task.Run()
和 Task.WhenAll()
方法。
组件概述
TaskExCum
是一个静态类,提供了以下主要功能:
实现步骤
接下来,我们将详细讲解 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
return Task.Run(function);#else
return Task.Factory.StartNew(
function,
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Default
);#endif}public static Task Run(Action action){#if NET45
return Task.Run(action);#else
return Task.Factory.StartNew(
action,
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Default
);#endif}
详细解释:
步骤 3: 实现 WhenAll
方法
WhenAll
方法用于等待多个任务完成,并收集所有任务的结果。我们为 WhenAll
方法提供了多种重载形式,以支持不同类型的任务集合。
public static Task<TResult[]> WhenAll<TResult>(IEnumerable<Task<TResult>> tasks){#if NET45
return Task.WhenAll(tasks);#else
return WhenAllCore(tasks);#endif}public static Task<TResult[]> WhenAll<TResult>(params Task<TResult>[] tasks){#if NET45
return Task.WhenAll(tasks);#else
return WhenAllCore(tasks);#endif}public static Task WhenAll(IEnumerable<Task> tasks){#if NET45
return Task.WhenAll(tasks);#else
return WhenAllCore(tasks);#endif}
详细解释:
步骤 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)
{
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}");
}
}
}
转自https://www.cnblogs.com/Bob-luo/p/18515670
该文章在 2024/11/6 9:24:43 编辑过