首页 > 编程语言 >CSharp (C#) 中创建Task 的7种方法对比,你用对了吗?

CSharp (C#) 中创建Task 的7种方法对比,你用对了吗?

时间:2025-01-02 13:26:39浏览次数:7  
标签:异步 Task Run C# 代码 任务 FromAsync CSharp

在C#编程中,Task是用于异步编程的重要工具之一。了解不同创建Task的方式以及它们之间的区别,对提高编程效率和代码质量至关重要。本文将详细探讨几种常见的Task创建方式,并分析它们的使用场景及优缺点。

一、使用Task.Run方法

1. 概述
Task.Run是最常见的一种创建Task的方式。它接受一个Action委托或Func委托作为参数,并将其放在线程池中的一个线程上执行。

2. 示例代码

Task task = Task.Run(() => {
    // 任务代码
});

3. 使用场景

-  当你有一个CPU密集型操作,并且希望它在后台线程上执行,从而不阻塞主线程时。
-  当需要并行处理多个任务以提高性能时。

4. 优缺点比较

优点:
-  简单易用。
-  自动管理线程生命周期。

缺点:
-  Task.Run方法 返回的Task表示的是一个“后台”任务,如果没有任何前台任务引用该后台任务,则该后台任务可能在GC回收时被终止。

二、使用Task.Factory.StartNew方法

1. 概述
Task.Factory.StartNew与Task.Run类似,但提供了更多的配置选项,比如可以设置任务的优先级等。

2. 示例代码

Task task = Task.Factory.StartNew(() => {
    // 任务代码
}, TaskCreationOptions.None);

3. 使用场景
-  当需要更细粒度地控制任务的创建和行为时,例如设置任务优先级。

4. 优缺点比较

优点:
-  提供了比Task.Run更多的配置选项。

缺点:
-  API相对复杂一些。
-  如果滥用高优先级,可能会导致应用程序的性能问题。

三、手动创建Task

1. 概述
有时你可能需要完全控制Task的创建过程,这时可以通过构造函数直接创建一个Task。

2. 示例代码

Task task = new Task(() => {
    // 任务代码
});

3. 使用场景
-  当需要在特定时机启动任务时,例如在特定的事件触发后。

4. 优缺点比较


优点:
-  提供了最大的灵活性和控制权。

缺点:
-  需要手动管理Task的状态,包括启动和异常处理。
-  更容易出错,特别是在忘记启动任务的情况下。

四、使用async和await关键字

1. 概述
在异步编程模型中,async和await关键字使得编写异步代码更加简洁和可读。实际上,编译器会将这些代码转换为状态机,以支持异步操作。

2. 示例代码

async Task MyAsyncMethod() {
    await Task.Delay(1000); // 模拟异步延时
}

3. 使用场景
-  当需要编写非阻塞性代码以提高应用响应性时。
-  当处理I/O密集型操作时。

4. 优缺点比较

优点:
-  语法简洁,易于阅读和维护。
-  自动处理异常和任务状态。

缺点:
-  如果过度使用,可能会导致上下文切换过多,影响性能。
-  在某些情况下,可能会引入复杂的错误处理逻辑。

五、使用TaskCompletionSource手动控制Task结果

1. 概述
TaskCompletionSource<T>允许开发者手动设置一个Task的结果或者完成状态。这对于实现自定义的异步操作非常有用。

2. 示例代码

TaskCompletionSource<int> taskTmp = new TaskCompletionSource<int>();

// 在某个地方完成任务
taskTmp .SetResult(100); // 或者其他结果

3. 使用场景
-  当需要创建一个可以手动控制的Task时,例如根据某些条件来设置结果。
-  当需要将同步代码包装为异步代码时。

4. 优缺点比较

优点:
-  提供了极大的灵活性,可以精确控制Task何时完成以及结果是什么。

缺点:
-  增加了代码复杂度。如果不小心,可能会导致资源泄漏或其他并发问题。

 六、使用 FromAsync方法(针对IAsyncResult接口)

1. 概述
对于那些已经实现IAsyncResult接口的老式异步方法,可以使用TaskFactory.FromAsync方法将其包装成一个Task对象。这有助于统一异步编程模式。

2. 示例代码

// 假设BeginSomeOperation返回IAsyncResult
IAsyncResult iar = BeginSomeOperation(); 

// EndSomeOperation为结束方法 
Task task = Task<int>.Factory.FromAsync(iar, EndSomeOperation);

3. 使用场景

TaskFactory.FromAsync 方法用于将基于两个异步方法(如 BeginMethod 和 EndMethod)的操作封装到一个单一的 Task 或 Task<TResult> 中。

4. 优缺点比较

优点:
使用 FromAsync 方法可以简化异步操作的代码,使得异步操作的代码看起来和同步操作的代码相似。
使用 FromAsync 方法可以避免使用回调,这样可以更容易地处理异常。
使用 FromAsync 方法可以利用.NET Framework的异步编程模型,这个模型已经过优化,可以提高程序的性能。

缺点:
如果使用不当,可能会导致代码变得更复杂,更难以理解。
如果异步操作在不同的线程上执行,那么可能会有性能上的开销,因为 FromAsync 需要创建额外的代理对象来处理异步操作。

七、ContinueWith方法添加后续任务

1. ContinueWith方法允许在一个Task完成后附加一个新的Task。这对于任务链式调用非常有用,可以确保前一个任务完成后再执行下一个任务。

2. 示例代码

Task task = Task.Run(() => {
    // 第一个任务
}).ContinueWith((t) => {
 
    if (t.IsFaulted) {
        Console.WriteLine("前一个任务失败!");
    } else {
        Console.WriteLine("前一个任务完成!");
    }
    // 其他逻辑代码
});

总结与建议
在选择Task的创建方式时,应该考虑具体的应用场景和需求。对于简单的后台任务,Task.Run是一个很好的选择;如果需要更多控制,可以考虑Task.Factory.StartNew;而对于异步I/O操作,则应该优先考虑使用async和await。此外,TaskCompletionSource<T>虽然强大,但也比较复杂,应谨慎使用。无论选择哪种方式,都应该确保对异常进行适当的处理,并且在必要时正确地释放资源。通过合理利用这些工具和技术,可以编写出高效且健壮的异步代码,提升用户体验和应用性能。

标签:异步,Task,Run,C#,代码,任务,FromAsync,CSharp
From: https://blog.csdn.net/m0_63998314/article/details/144805038

相关文章

  • 让 Java 再次伟大 - 你不知道的 Java 之集成 Docker 的那些密事(一章节)
    学会这款全新设计的Java脚手架,从此面试不再怕!Docker的底层实现原理Docker是一种容器服务,为了方便理解你可以认为他是一个轻量级的虚拟机。通过Docker创建的容器,在宿主机上共享硬件资源和底层系统与接口,同时又能提供互相隔离的应用程序环境。这是怎么做到的?由于......
  • 2025/1/2 【双指针法】LeetCode27.移除元素 【√】 ❗未完结❗
    27.移除元素-力扣(LeetCode)代码随想录数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。Myanswer:快慢指针法classSolution:defremoveElement(self,nums:List[int],val:int)->int:n=len(nums)j=0forii......
  • opencv中findCirclesGrid在标定时使用,blobDetector 参数怎么定义?
    在OpenCV中,findCirclesGrid是一个用于检测图像中的圆形格点(通常用于相机标定或校正的检测目标)的函数。它可以用于查找在特定模式下排列的圆形图案,如棋盘格或圆形网格。该函数是相机标定和立体视觉的重要工具。函数原型boolcv::findCirclesGrid(InputArrayimage,S......
  • 关于此题E - Maximize XOR(Atcoder ABC 386)搜索技巧的一些总结
    传送门题目要求n个数中选k个数异或起来最大,我们想到字典树中最大异或和这一经典问题,但是很明显字典树只能解决任选两个数的最大异或,而此题是任选k个,那我们走投无路只能考虑爆搜。首先可以很容易写出一个暴力的搜索:voiddfs1(longlongpos,longlongsum,longlongkk){i......
  • [Qt] 万字详解Qt入门~ Qt Creator | 对象树 | 控件布局
    目录1.QtCreator概览2.使用QtCreator新建项目3.认识QtCreator界面4.QtHelloWorld程序1.使用“按钮”实现2.使用“标签”实现3.使用“编辑框”实现5.项目文件解析1.命名空间声明与作用2.classWidget:publicQWidget6.Qt编程注意事项......
  • Pycharm中AI Assistant怎么使用
    当我更新了pycharm到2024.3版本后,发现内置了Jetbrains的aiassistant插件,并且有免费试用的时间,但是并不对中国大陆用户开放,只对提供了openai的地区开放,接下来讲一下我怎么使用的aiassistant,1、安装所需插件 在左上角file-settings中的Plugins的搜索框中查找图中插件并下载......
  • 【算法一周目】位间流转,数字律动——洞察 C++ 位运算中的精妙与哲思
    文章目录常见位运算1.位1的个数2.比特位计数3.汉明距离4.只出现一次的数字5.只出现一次的数字III6.只出现一次的数字II7.判定字符是否唯一8.丢失的数字9.两整数之和10.只出现一次的数字II常见位运算判断一个数的二进制表示的第x位是0还是1(n>>x)&1......
  • 【Java项目】基于SpringBoot+Vue的CSGO赛事管理系统
    源码获取:https://download.csdn.net/download/u011832806/89461573基于SpringBoot+Vue的CSGO赛事管理系统开发语言:Java数据库:MySQL技术:SpringBoot+MyBatis+Vue.js工具:IDEA/Ecilpse、Navicat、Maven系统演示视频:链接:https://pan.baidu.com/s/109zhbBkTfpLZJx0Twg2afg?pw......
  • lsync服务使用hlim用户进行同步配置
    一、首先两台服务器做hlim用户的免密ssh登录su-hlimssh-keygen-trsassh-keygen-trsa-f/home/hlim/.ssh/id_rsa-P""在目标服务器上执行,将另外一台服务器的/home/hlim/.ssh/id_rsa.pub内容复制到/home/hlim/^Csh/authorized_keys中 su-hlimvim.ssh/authorize......
  • 浅谈以 Oracle 为基准,GaussDB、达梦数据库(DM)和 PostgreSQL 的差异以及信创前景
    随着国内信息技术的快速发展,尤其是在“信息技术自主可控”(即信创)政策的推动下,国内企业和政府部门逐渐对数据库技术提出了自主可控的需求。尤其在数据库领域,国产数据库技术的崛起,正逐步替代传统的国际主流数据库系统(如Oracle等),成为我国数字化转型和数据安全战略中的关键一环。本......