引言
隨著 .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 編輯過