引言
隨著 .NET 技術(shù)的發(fā)展,異步編程模型逐漸成為現(xiàn)代應(yīng)用程序開(kāi)發(fā)中的標(biāo)準(zhǔn)實(shí)踐之一。.NET 4.5 引入了 Task
類(lèi),極大地簡(jiǎn)化了異步編程的過(guò)程。然而,許多遺留系統(tǒng)仍在使用 .NET 4.0 或更低版本,這些版本并未直接支持 Task
類(lèi)的全部功能。為此,我們開(kāi)發(fā)了 TaskExCum
組件,旨在為 .NET 4.0 提供與 .NET 4.5 相似的 Task
功能,包括 Task.Run()
和 Task.WhenAll()
方法。
組件概述
TaskExCum
是一個(gè)靜態(tài)類(lèi),提供了以下主要功能:
實(shí)現(xiàn)步驟
接下來(lái),我們將詳細(xì)講解 TaskExCum
組件的實(shí)現(xiàn)步驟,以便讀者能夠更好地理解其工作原理,并將其應(yīng)用于自己的項(xiàng)目中。
步驟 1: 創(chuàng)建 TaskExCum
類(lèi)
首先,我們需要?jiǎng)?chuàng)建一個(gè)靜態(tài)類(lèi) TaskExCum
,并在其中定義靜態(tài)方法。
public static class TaskExCum{
}
步驟 2: 實(shí)現(xiàn) Run
方法
Run
方法允許開(kāi)發(fā)者異步執(zhí)行任務(wù),并獲取任務(wù)的結(jié)果。我們?yōu)?nbsp;Run
方法提供了兩種重載形式,分別用于執(zhí)行無(wú)返回值的操作(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}
詳細(xì)解釋:
條件編譯:使用 #if NET45
編譯符號(hào),當(dāng)項(xiàng)目目標(biāo)框架為 .NET 4.5 及更高版本時(shí),使用 Task.Run
方法。
Task.Factory.StartNew:當(dāng)項(xiàng)目目標(biāo)框架為 .NET 4.0 時(shí),使用 Task.Factory.StartNew
方法來(lái)啟動(dòng)任務(wù)。
CancellationToken.None:表示沒(méi)有取消令牌,任務(wù)不會(huì)被外部取消。
TaskCreationOptions.None:表示沒(méi)有特殊的任務(wù)創(chuàng)建選項(xiàng)。
TaskScheduler.Default:這是關(guān)鍵點(diǎn)之一。TaskScheduler.Default
表示使用默認(rèn)的線程池調(diào)度器,這意味著任務(wù)會(huì)在線程池中的一個(gè)線程上執(zhí)行,而不是每次都啟動(dòng)一個(gè)新的線程。這有助于提高性能和資源利用率。
步驟 3: 實(shí)現(xiàn) WhenAll
方法
WhenAll
方法用于等待多個(gè)任務(wù)完成,并收集所有任務(wù)的結(jié)果。我們?yōu)?nbsp;WhenAll
方法提供了多種重載形式,以支持不同類(lèi)型的任務(wù)集合。
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}
詳細(xì)解釋:
條件編譯:使用 #if NET45
編譯符號(hào),當(dāng)項(xiàng)目目標(biāo)框架為 .NET 4.5 及更高版本時(shí),使用 Task.WhenAll
方法。
WhenAllCore:當(dāng)項(xiàng)目目標(biāo)框架為 .NET 4.0 時(shí),調(diào)用 WhenAllCore
方法來(lái)實(shí)現(xiàn)相同的功能。
步驟 4: 實(shí)現(xiàn) WhenAllCore
方法
WhenAllCore
方法是 WhenAll
方法的核心實(shí)現(xiàn),負(fù)責(zé)處理任務(wù)集合,等待所有任務(wù)完成,并收集結(jié)果或異常信息。
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;
}
詳細(xì)解釋:
參數(shù)驗(yàn)證:檢查傳入的任務(wù)集合是否為 null
,如果是,則拋出 ArgumentNullException
。
TaskCompletionSource:創(chuàng)建一個(gè) TaskCompletionSource
對(duì)象,用于管理任務(wù)的完成狀態(tài)。
任務(wù)轉(zhuǎn)換:將任務(wù)集合轉(zhuǎn)換為數(shù)組,以便于后續(xù)處理。
任務(wù)數(shù)量檢查:如果任務(wù)集合為空,直接調(diào)用 setResultAction
設(shè)置結(jié)果。
等待所有任務(wù)完成:使用 Task.Factory.ContinueWhenAll
方法等待所有任務(wù)完成。
異常處理:遍歷已完成的任務(wù),收集所有失敗任務(wù)的異常信息。
取消處理:檢查是否有任務(wù)被取消。
設(shè)置結(jié)果:如果沒(méi)有異常且沒(méi)有任務(wù)被取消,調(diào)用 setResultAction
設(shè)置結(jié)果。
TaskScheduler.Default:這里再次使用 TaskScheduler.Default
,確保任務(wù)在默認(rèn)的線程池中執(zhí)行,而不是每次都啟動(dòng)新的線程。
步驟 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);
}
}
詳細(xì)解釋:
異常類(lèi)型檢查:檢查傳入的異常是否為 AggregateException
。
異常列表初始化:如果 targetList
為 null
,則初始化一個(gè)新的列表。
異常添加:根據(jù)異常的類(lèi)型,將異常或其內(nèi)部異常添加到列表中。
示例代碼
為了幫助讀者更好地理解如何使用 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}");
}
}
}
轉(zhuǎn)自https://www.cnblogs.com/Bob-luo/p/18515670
該文章在 2024/11/6 9:24:43 編輯過(guò)