首页 > 其他分享 >实现.NET 4.0下的Task类相似功能组件

实现.NET 4.0下的Task类相似功能组件

时间:2024-10-31 08:58:34浏览次数:1  
标签:tasks 4.0 WhenAllCore 任务 Task NET WhenAll

实现 .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
  • 异常列表初始化:如果 targetListnull,则初始化一个新的列表。
  • 异常添加:根据异常的类型,将异常或其内部异常添加到列表中。

示例代码

为了帮助读者更好地理解如何使用 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://www.cnblogs.com/Bob-luo/p/18515670
以上就是关于 TaskExCum 组件的详细介绍。希望通过这篇文章,读者能够更好地理解和使用这个组件,从而在自己的项目中实现高效的异步编程。如果有任何问题或需要进一步的帮助,请随时留言!

标签:tasks,4.0,WhenAllCore,任务,Task,NET,WhenAll
From: https://www.cnblogs.com/Bob-luo/p/18515670

相关文章

  • YOLOv6-4.0部分代码阅读笔记-data_augment.py
    data_augment.pyyolov6\data\data_augment.py目录data_augment.py1.所需的库和模块2.defaugment_hsv(im,hgain=0.5,sgain=0.5,vgain=0.5): 3.defletterbox(im,new_shape=(640,640),color=(114,114,114),auto=True,scaleup=True,stride=32): 4.defmixup(......
  • 什么是Internet 和 Internet的性能指标
    Internet和它的性能指标请时刻注意,Internet也是网络,它是一些相互连接的节点的集合。互联网(Internet)从宏观上看,它是一个由软件与硬件的集合组成的分布式系统。这个系统主要为用户提供的服务就是通信。互联网的组成硬件:一些物理链路(用于连接)和用于通信的硬件节点(路由器......
  • 计算机网络(们)和 Internet (计算机网络的子类)
    计算机网络101计算机网络,属于网络的一种。网络通常指由多个节点和它们之间的连接关系构成的结构,强调连接、交互和通信。说明网络的主要目的是通信(交流)(通信)历史以前使用广播,不管是物理的还是无线电广播。特点:强调的是信息的单向传递。用户只能接收信息,而不能实时反馈。(这......
  • Apache Commons Net 共享SSLSession问题解决
        某些服务器会默认开启TLS会话恢复,如FileZillaServer1.0及以后的版本(相对于1.0以前版本就是先当与勾选了RequireTLSsessionresumptionondataconnectwhenusingPORTP)。ApacheCommonsNet目前是不支持TLS会话恢复的,所以我们只能通过重写FTPSClient来实现。不然你......
  • dotnet core微服务框架Jimu ~ 会员授权微服务
    提供授权服务,用户使用会员的用户名和密码获取token,带着token访问受保护的接口,如浏览和发布新闻。有2个公开的api:token:获取token;GetCurrentMemberInfo:获取当前token的会员信息;有1个不公开的方法:GetMemberInfo:根据会员用户名和密码,获取会员信息,该方法供......
  • CSCI 201 Networked Crossword Puzzle
    Assignment#2CSCI201Fall2024Page1of11Assignment#2CSCI201Fall20246%ofcoursegradeTitleNetworkedCrosswordPuzzleTopicsCoveredNetworkingMulti-ThreadingConcurrencyIssuesIntroductionThisassignmentwillrequireyoutocreatetwodiffe......
  • 管中窥豹----从String Intern中观察.NET Core到.NET 8 托管堆的变迁
    简介https://www.cnblogs.com/lmy5215006/p/18494483在研究.NETString底层结构时,我所观察到的情况与《.NETCore底层入门》,《.NET内存管理宝典》书中描述不符。故多研究了一下。发现.NET托管堆的结构也是越来越多,越来越高性能。 //示例代码internalclassProgram{......
  • 为.Net项目添加动态库加载路径
    为.Net项目添加动态库加载路径_51CTO博客_linux动态库加载路径本文分别基于.NetFramework和.NetCore的WPF应用程序为例,来说明如何为.Net项目添加自定义动态库加载路径。本文基于.NetCore创建WPF时,使用了.Net5作为目标框架。1、.NetFramework在基于.NetFramework的WPF项目......
  • 使用asp.net mvc 过程中 参数传递的问题记录。
    环境:asp.netMVC需求:要实现主从表数据存储,主表为结构化信息,附表为对应的图片。实现过程:页面中当用户在新建数据的时候,未保存时没有主表的主键,同时用户也会选择要上传的图片一同保存。 使用ajaxfileupload.js实现多文件上传,上传之后通过window.URL.createObjectURL将上传......
  • .NET中的线程池ThreadPool(链接)
    微软推荐在.NET中使用多线程开发时,都使用线程池,下面这篇微软文档介绍了.NET中的线程池类ThreadPool:ThreadPoolClass注意上面文档中的这句话:Thereisonethreadpoolperprocess.也就是说,每个.NET进程(process)中有一个线程池,线程池在每个.NET进程中只有一个,一个.NET进程中......