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 来实现。

相关推荐
津津有味道42 分钟前
Ntag 424 DNA写入URI网址配置开启动态UID计数器镜像C#源码
c#·uri·ndef·424dna·动态uid·计数器镜像
万19994 小时前
asp.net core webapi------3.AutoMapper的使用
c#·.netcore
唐青枫4 小时前
C#.NET 路由机制深入解析:从传统路由到 Endpoint Routing
c#·.net
hixiong12315 小时前
C# OpenCVSharp使用 读光-票证检测矫正模型
人工智能·opencv·c#
霜绛15 小时前
C#知识补充(二)——命名空间、泛型、委托和事件
开发语言·学习·unity·c#
好望角雾眠15 小时前
第四阶段C#通讯开发-6:Socket之UDP
开发语言·笔记·学习·udp·c#
霜绛16 小时前
C#知识补充(一)——ref和out、成员属性、万物之父和装箱拆箱、抽象类和抽象方法、接口
开发语言·笔记·学习·c#
爱编程的鱼17 小时前
C# var 关键字详解:从入门到精通
开发语言·c#·solr
玩泥巴的18 小时前
解放双手!使用Roslyn生成代码让你的 HTTP 客户端开发变得如此简单
c#·.net·代码生成·roslyn
星释19 小时前
Rust 练习册 :Pig Latin与语言游戏
游戏·rust·c#