Task异步的常用方法
C# 中的 Task 类是 System.Threading.Tasks 命名空间的一部分,用于表示异步操作。
一、Task.Run(Action action):
此静态方法用于在后台运行一个新任务,并返回与该任务关联的 Task 实例。
- 本质是将任务放入线程池执行,自动启动,适合CPU 密集型或简单异步操作。
- 注意:返回的
Task
无法手动控制启动(已自动启动)。
Task.Run(() => Console.WriteLine("后台执行"));
二、Task.Start():
用于手动启动通过 new Task(...)
创建的未启动任务(默认状态为 Created
)。
var task = new Task(() => Console.WriteLine("手动启动"));
task.Start(); // 必须调用才会执行
三、Task.Delay(int millisecondsDelay):
此静态方法创建一个在指定延迟之后完成的 Task。这对于定时操作或模拟长时间运行的任务非常有用。
await Task.Delay(1000); // 等待1秒
四、任务等待相关方法(阻塞 vs 非阻塞)
方法 | 特性 | 适用场景 |
---|---|---|
await Task.WhenAll | 非阻塞等待所有任务完成 | 异步方法中,需要等待多个任务全部完成后再继续 |
await Task.WhenAny | 非阻塞等待任一任务完成 | 异步方法中,只需等待最快完成的任务结果 |
Task.WaitAll | 阻塞当前线程等待所有任务 | 同步方法中强制等待(不推荐在异步代码中使用) |
Task.WaitAny | 阻塞当前线程等待任一任务 | 同步方法中需立即响应第一个完成的任务 |
Task.Wait() | 阻塞当前线程等待单个任务 | 同步方法中等待单个任务(等价于 WaitAll 单任务) |
关键区别:
await
搭配WhenAll
/WhenAny
是非阻塞等待,会释放当前线程,适合异步上下文(如 UI 线程),避免界面卡顿。Wait()
/WaitAll()
/WaitAny()
是阻塞等待,会冻结当前线程,可能导致性能问题(如 UI 无响应),仅建议在纯同步代码中使用。
1.Task.WhenAll(Task[] tasks):
注意:由于此调用不会默认等待,需要再前面添加await。
var task1 = Task.Run(() => { /* 任务1 */ });
var task2 = Task.Run(() => { /* 任务2 */ });await Task.WhenAll(task1, task2);
2.Task.WhenAny(Task[] tasks):
注意:由于此调用不会默认等待,需要再前面添加await。
var task1 = Task.Run(() => { /* 任务1 */ });
var task2 = Task.Run(() => { /* 任务2 */ });var completedTask = await Task.WhenAny(task1, task2);
3.Task.Wait():
var task = Task.Run(() => { /* 代码 */ });
task.Wait();
4.Task.WaitAll(Params Task[])
var task1 = Task.Run(() => { /* 任务1 */ });
var task2 = Task.Run(() => { /* 任务2 */ });var completedTask = Task.WaitAll(task1, task2);
5.Task.WaitAny(Params Task[])
var task1 = Task.Run(() => { /* 任务1 */ });
var task2 = Task.Run(() => { /* 任务2 */ });var completedTask = Task.WaitAny(task1, task2);
五、Task.ContinueWith(Action continuationAction):
此方法用于在当前任务完成后执行另一个操作。这对于链式(嵌套)任务执行非常有用。(等待一个任务完成)
// 正常情况下 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 来实现。