C# Task异步的常用方法

Task异步的常用方法

C# 中的 Task 类是 System.Threading.Tasks 命名空间的一部分,用于表示异步操作。

一、Task.Run(Action action):

此静态方法用于在后台运行一个新任务,并返回与该任务关联的 Task 实例。

  1. 本质是将任务放入线程池执行,自动启动,适合CPU 密集型或简单异步操作
  2. 注意:返回的 Task 无法手动控制启动(已自动启动)。
cs 复制代码
Task.Run(() => Console.WriteLine("后台执行"));

二、Task.Start():

用于手动启动通过 new Task(...) 创建的未启动任务 (默认状态为 Created)。

cs 复制代码
var task = new Task(() => Console.WriteLine("手动启动"));
task.Start(); // 必须调用才会执行

三、Task.Delay(int millisecondsDelay):

此静态方法创建一个在指定延迟之后完成的 Task。这对于定时操作或模拟长时间运行的任务非常有用。

cs 复制代码
await Task.Delay(1000); // 等待1秒

四、任务等待相关方法(阻塞 vs 非阻塞)

方法 特性 适用场景
await Task.WhenAll 非阻塞等待所有任务完成 异步方法中,需要等待多个任务全部完成后再继续
await Task.WhenAny 非阻塞等待任一任务完成 异步方法中,只需等待最快完成的任务结果
Task.WaitAll 阻塞当前线程等待所有任务 同步方法中强制等待(不推荐在异步代码中使用)
Task.WaitAny 阻塞当前线程等待任一任务 同步方法中需立即响应第一个完成的任务
Task.Wait() 阻塞当前线程等待单个任务 同步方法中等待单个任务(等价于 WaitAll 单任务)

关键区别

  1. await 搭配 WhenAll/WhenAny非阻塞等待,会释放当前线程,适合异步上下文(如 UI 线程),避免界面卡顿。
  2. Wait()/WaitAll()/WaitAny()阻塞等待 ,会冻结当前线程,可能导致性能问题(如 UI 无响应),仅建议在纯同步代码中使用。

1.Task.WhenAll(Task\[\] tasks):

注意:由于此调用不会默认等待,需要再前面添加await。

cs 复制代码
var task1 = Task.Run(() => { /* 任务1 */ });
var task2 = Task.Run(() => { /* 任务2 */ });
 
await Task.WhenAll(task1, task2);

2.Task.WhenAny(Task\[\] tasks):

注意:由于此调用不会默认等待,需要再前面添加await。

cs 复制代码
var task1 = Task.Run(() => { /* 任务1 */ });
var task2 = Task.Run(() => { /* 任务2 */ });
 
var completedTask = await Task.WhenAny(task1, task2);

3.Task.Wait():

cs 复制代码
var task = Task.Run(() => { /* 代码 */ });
task.Wait();

4.Task.WaitAll(Params Task\[\])

cs 复制代码
var task1 = Task.Run(() => { /* 任务1 */ });
var task2 = Task.Run(() => { /* 任务2 */ });
 
var completedTask = Task.WaitAll(task1, task2);

5.Task.WaitAny(Params Task\[\])

cs 复制代码
var task1 = Task.Run(() => { /* 任务1 */ });
var task2 = Task.Run(() => { /* 任务2 */ });
 
var completedTask = Task.WaitAny(task1, task2);

五、Task.ContinueWith(Action continuationAction):

此方法用于在当前任务完成后执行另一个操作。这对于链式(嵌套)任务执行非常有用。(等待一个任务完成)

cs 复制代码
// 正常情况下 t1 和 t2 不知道谁先执行完
Task<string> t1 = new Task<string>(F1);
Task<string> t2 = new Task<string>(F2);
Task<string> t3 = new Task<string>(F3);
 
//t1先执行 t2后执行 
t1.ContinueWith(t =>
{
    // t1执行完之后 再去执行
    t2.Start(); //第二任务
    t2.ContinueWith(t4 =>
    {
        //第二个任务完成了
        //第三个任务对象
        t3.Start();
        t3.ContinueWith(t5 =>
        {
            Console.WriteLine("保证第三个任务完成");
        });
    });
});

注意:在使用 Task 类时,应始终考虑处理异常和取消操作。这可以通过使用 try-catch 语句和 CancellationToken 来实现。

相关推荐
淡海水12 分钟前
13-04-面试-源码级深度追问链
数据结构·unity·面试·c#·游戏引擎·源码·il2cpp
asdzx671 小时前
如何使用 C# 提取 PPT 文本与图片
c#·ppt·提取文本
2501_930707788 小时前
使用C#代码使用条件格式为 Excel 隔行设置颜色
c#·excel
何以解忧唯有撸码11 小时前
【开源】c#造个轮子-日程安排工具
c#·自定义控件
周杰伦fans12 小时前
CAD菜单栏和工具栏都不见了,怎么显示?
其他·c#
曹牧12 小时前
C#:HashSet<T> 去重
c#
czhc114007566312 小时前
起点、口径与因果:今天用错的七把尺子
c#
c#上位机1 天前
C#上位机项目实战——Task.Run执行带参数的方法
c#·上位机
Lost of 程序猿1 天前
用 YARP 为 .NET 微服务搭一座“立交桥“:路由转发与生产配置实践
c#·asp.net
点纭1 天前
C 语言 第七章 常用函数(3)
c语言·开发语言·算法·oracle·c#