当前位置: 首页 > news >正文

.NET 任务 Task、Task.Run()、 Task.WhenAll()、Task.WhenAny()

文章目录

  • 前言
  • 什么是 Task?
  • 为什么要使用 Task?
  • 如何使用 Task?
    • (1)使用 Task.Run()
    • (2)使用 async/await
  • 在什么地方使用 Task?
  • 使用优缺点
  • 如何从任务中返回值
    • 使用 async/await 返回值
    • 使用 Task.Run() 返回值
    • 使用 Continuation(任务续接)
    • 使用 TaskCompletionSource
    • 总结
  • 如何执行多个任务
    • 为什么需要多个任务?
    • 如何执行多个任务?
  • 使用 Task.WhenAll() 执行多个任务
  • 使用 Task.WhenAny() 执行多个任务
  • 总结
    • 为什么需要多个任务?
    • 如何执行多个任务?
    • 应用场景:


前言

转载: 方程式sunny

视频教程: 跟着sunny老师学C#

源码: gitee仓库


什么是 Task?


C#中,Task 是一个表示异步操作的对象。简单来说,Task 让你能够在后台运行代码,而不需要等待这个操作完成,从而保持程序的响应性。


想象你在一家餐厅点了一道菜。当你点完后,服务员将你的订单传给厨房,然后你可以继续聊天或看手机,而不需要一直等待菜上桌。这个过程就类似于使用 Task:你发出请求(执行任务),然后继续做其他事情(继续执行程序)。


为什么要使用 Task?

使用 Task 的主要原因是为了提高程序的性能和响应性。特别是在处理耗时的操作(例如网络请求、文件读写等)时,使用 Task 可以:

  • 提升用户体验:用户界面不会因为等待操作而卡顿。
  • 提高资源利用率:能够同时执行多个任务,从而更好地利用系统资源。

如何使用 Task?


(1)使用 Task.Run()

这是最常见的方式,适合简单的异步操作:

using System;
using System.Threading.Tasks;class Program
{static void Main(){Task task = Task.Run(() => {for (int i = 0; i < 5; i++){Console.WriteLine($"Task running: {i}");}});
​task.Wait(); // 等待任务完成Console.WriteLine("Task completed.");}
}

(2)使用 async/await

使用 asyncawait 关键字,使得异步代码更加简洁:

async Task MainAsync()
{await Task.Run(() => {// 模拟耗时操作for (int i = 0; i < 5; i++){Console.WriteLine($"Task running: {i}");}});
​Console.WriteLine("Task completed.");
}

在什么地方使用 Task?

Task 特别适合以下场景:

  1. I/O 操作:如读取文件、网络请求等。
  2. 长时间运行的计算:如复杂的数据处理。
  3. 多任务并行处理:如同时处理多个用户请求。

使用优缺点

优点:

  1. 简化异步编程:Task 提供了更高层次的抽象,简化了异步编程的复杂性。
  2. 错误处理更简单:通过AggregateException 处理多个异常。
  3. 可取消:使用 CancellationToken 可以轻松取消任务。

缺点:

  1. 资源管理:过多的并发任务可能会导致资源竞争和性能下降。
  2. 调试难度:异步代码可能会增加调试的复杂性,特别是错误追踪。

如何从任务中返回值

C# 中,使用 Task<T> 可以轻松实现异步方法的返回值。下面重点介绍几种常见的方法来从任务中返回值,并在代码注释中提供解析。


使用 async/await 返回值

using System;
using System.Threading.Tasks;class Program
{static async Task Main(string[] args){// 调用异步方法并等待其返回结果int result = await CalculateSumAsync(5, 10);Console.WriteLine($"计算结果: {result}");}static async Task<int> CalculateSumAsync(int a, int b){// 模拟一个耗时的异步操作await Task.Delay(1000);return a + b; // 返回计算结果}
}

使用 Task.Run() 返回值

using System;
using System.Threading.Tasks;class Program
{static void Main(){// 使用 Task.Run 启动一个新任务来执行计算Task<int> task = Task.Run(() => {return Calculate(5, 10); // 执行计算并返回结果});// 等待任务完成并获取结果int result = task.Result; Console.WriteLine($"计算结果: {result}");}static int Calculate(int a, int b){return a + b; // 返回计算结果}
}

使用 Continuation(任务续接)

using System;
using System.Threading.Tasks;class Program
{static void Main(){// 启动任务来执行计算Task<int> task = Task.Run(() => Calculate(5, 10));// 使用 ContinueWith 在任务完成后处理结果task.ContinueWith(t => {Console.WriteLine($"计算结果: {t.Result}"); // 获取原任务的返回值});// 等待用户输入,以便查看结果Console.ReadLine();}static int Calculate(int a, int b){return a + b; // 返回计算结果}
}

使用 TaskCompletionSource

using System;
using System.Threading.Tasks;class Program
{static void Main(){// 创建 TaskCompletionSource 来手动控制任务的完成var tcs = new TaskCompletionSource<int>();
​Task.Run(() =>{// 模拟耗时操作Task.Delay(1000).Wait();tcs.SetResult(42); // 设置任务的结果});// 获取任务的结果,等待并获取结果int result = tcs.Task.Result; Console.WriteLine($"计算结果: {result}");}
}

总结

C# 中,通过 Task<T> 和相关的方法,可以方便地从异步任务中返回值。主要的几种方法包括:

  1. async/await:最常用的方法,简单明了。
  2. Task.Run():适合简单的计算并直接返回结果。
  3. Continuation:用于在任务完成后执行后续操作。
  4. TaskCompletionSource:手动控制任务的完成,适用于更复杂的场景。

如何执行多个任务

Task.WhenAll()
Task.WhenAny()


为什么需要多个任务?

在实际开发中,特别是涉及 耗时操作 或 并行任务 的情况,通常会遇到以下问题:

  • (1)等待操作完成: 比如进行文件 I/O、网络请求等操作时,如果按照顺序执行,每一步操作都需要等待前一个操作完成,这会导致程序的响应性差。
  • (2)资源利用率低: 如果操作能够并行进行,可以大大提高程序的效率和资源利用率。

为了提高程序性能和响应性,我们常常需要 并行执行多个任务。通过将任务分配到不同的线程或处理器核心,可以在等待一个任务完成的同时,继续执行其他任务,避免资源闲置。例如:

  • (1)如果你需要从多个服务器获取数据,等待每个请求的响应会浪费时间。通过并行发送请求并等待所有响应,可以节省大量的时间。
  • (2)如果你需要执行多个计算任务,顺序执行会导致时间上的浪费。并行处理可以加快结果的获得。

如何执行多个任务?

C# 提供了多种方式来并行执行多个任务,主要有以下两种方法:

  • (1)Task.WhenAll():等待所有任务完成。
  • (2)Task.WhenAny():等待任意一个任务完成。
    这两种方法可以根据不同的需求选择,接下来我将通过代码示例来讲解每种方法的使用。

使用 Task.WhenAll() 执行多个任务

  • Task.WhenAll()方法用于并行执行多个任务,并且只有当所有任务都完成时,才会继续执行后续代码。
  • 这个方法适用于你需要等待 所有任务 完成后,才能继续做其他事情的场景。

示例:

using System;
using System.Threading.Tasks;class Program
{static async Task Main(string[] args){// 启动多个异步任务(这里模拟的是3个耗时的任务)Task task1 = Task.Run(() => DoWork(1)); // 第一个任务Task task2 = Task.Run(() => DoWork(2)); // 第二个任务Task task3 = Task.Run(() => DoWork(3)); // 第三个任务// Task.WhenAll() 等待所有任务完成,只有所有任务都完成后才会继续执行await Task.WhenAll(task1, task2, task3);// 当所有任务都完成时输出消息Console.WriteLine("所有任务完成!");}static void DoWork(int taskId){// 模拟每个任务的耗时操作(例如网络请求、计算任务等)Task.Delay(1000).Wait();  // 等待1秒Console.WriteLine($"任务 {taskId} 完成"); // 打印任务完成信息}
}

解释:

  • 在这个例子中,我们通过 Task.Run() 启动了 3 个异步任务,模拟了执行耗时操作(如计算、I/O 操作等)。
  • Task.WhenAll() 等待所有任务完成。只有当所有任务都完成后,控制台才会输出 “所有任务完成!”。
  • 这种方式适用于 所有任务都必须完成后才需要执行的场景。
  • 例如,等待多个文件下载完毕后再处理它们,或者等多个数据源都准备好数据后再开始处理。

应用场景:

  • (1) 网络请求:例如,你同时向多个 API 发起请求,并在所有请求返回后进行处理。
  • (2) 数据处理:同时进行多个计算任务,等待所有计算完成后汇总结果。

使用 Task.WhenAny() 执行多个任务

  • Task.WhenAny() 方法等待多个任务中的任意一个完成,一旦有任务完成,后续代码会立即执行。
  • 这适用于你只关心 最先完成的任务,而不需要等所有任务都完成的场景。

示例:

using System;
using System.Threading.Tasks;class Program
{static async Task Main(string[] args){// 启动多个异步任务(这里模拟的是3个耗时的任务)Task task1 = Task.Run(() => DoWork(1)); // 第一个任务Task task2 = Task.Run(() => DoWork(2)); // 第二个任务Task task3 = Task.Run(() => DoWork(3)); // 第三个任务// Task.WhenAny() 等待任意一个任务完成,并且一旦有任务完成就继续执行Task firstCompletedTask = await Task.WhenAny(task1, task2, task3);// 输出第一个完成任务的信息Console.WriteLine($"至少有一个任务完成!任务编号:{firstCompletedTask.Id}");}static void DoWork(int taskId){// 模拟每个任务的耗时操作(例如网络请求、计算任务等)Task.Delay(1000).Wait();  // 等待1秒Console.WriteLine($"任务 {taskId} 完成"); // 打印任务完成信息}
}

解析:

  • Task.WhenAny() 只等待 第一个完成的任务,无论是 task1task2 还是 task3,只要有一个任务先完成,就会继续执行后续代码。
  • 该方法返回的是 第一个完成的任务,在这里我们打印该任务的 ID
  • 这种方式适用于你只关心最先完成的任务的场景。比如你发起了多个网络请求,但只关心第一个请求的响应。

应用场景:

  • (1)网络请求:例如,向多个服务器请求数据,但你只关心最快返回的一个响应。
  • (2)响应优先:在多个计算任务中,你只关心最早完成的任务,并基于其结果执行后续操作。

总结

为什么需要多个任务?

  • 在处理多个耗时操作时,顺序执行会浪费大量时间。
  • 通过并行执行多个任务,可以显著提高程序的效率和响应速度。

如何执行多个任务?

  • (1)Task.WhenAll():等待所有任务完成后才继续执行。适用于所有任务都必须完成后才能做进一步处理的场景。
  • (2)Task.WhenAny():等待任意一个任务完成。一旦某个任务完成,就立即继续执行后续代码,适用于你只关心最先完成的任务。

应用场景:

  • (1)Task.WhenAll() 适用于需要等所有任务完成后才继续处理的场景(如并行下载多个文件、计算多个数据源的结果等)。
  • (2)Task.WhenAny() 适用于只关心第一个完成的任务的场景(如响应最早的网络请求或最先完成的计算任务)。

http://www.dtcms.com/a/532105.html

相关文章:

  • 英文营销网站建设南京成旭通网站建设公司怎么样
  • wordpress如何做站群关键词优化易下拉效率
  • 面试官问 Linux 编译调试?gcc 编译流程 + gdb 断点调试 + git 版本控制,连 Makefile 都标好了
  • C语言练习题(二)
  • 【QSS】软件界面的美工操作——Qt 界面优化
  • 网页版html编辑器手机优化大师
  • 【思想比实现更重要】高并发场景下如何保证接口幂等性
  • Spring Expression Language (SpEL) 详解:功能强大的表达式引擎
  • LeetCode:773. 滑动谜题
  • MATLAB基于类别加权灰靶决策的教学评价研究
  • C16可变参数模板函数和普通函数模板
  • 网站建设规划设计方案建设部门电工证查询网站
  • ​​lseek​​的“时空跳跃”:从获取大小到制造“文件空洞”
  • 技术演进中的开发沉思-151 java-servlet:会话管理
  • 【IO多路转接】IO 多路复用之 select:从接口解析到服务器实战
  • 淄博周村学校网站建设定制wordpress文章和页面
  • Multitouch for mac 触控板多点手势创建
  • SIGCHLD:进程终止与僵尸进程清理的关键
  • 数据结构(10)
  • 南皮做网站的团队管理的七个要点
  • Mysql的数据备份和高可用
  • 【Kotlin】数组集合常用扩展函数
  • css新增盒子属性——尺寸调节
  • 做阿里国际网站会有成效吗上海网站建设公司招人
  • 【课堂笔记】概率论-3
  • 【硬件基础篇】:CPU如何被制造出来
  • 面向模块的综合技术之控制集优化(七)
  • 做网站广告软件网站系统设计目标
  • 使用稀疏采样方法减轻汽车雷达干扰——论文阅读
  • 阮一峰《TypeScript 教程》学习笔记——d.ts 类型声明文件