Task任务重点掌握
概念:Task是微软在.Net4.0时代推出来的,也是微软极力未推荐的一种多线程的处理方式,Task看起来像一个Thread,实际上,它是在ThreadPool的基础上进行的封装,Task的控制和扩展性很强,在线程的延续,阻塞,取消,超时等方面远胜于Thread和 ThreadPool.核心优势在于:
- 内置任务生命周期管理(创建、运行、完成、取消等状态)
- 支持任务延续、组合与依赖管理
- 原生支持取消、超时和异常处理
- 更高效的线程复用(减少线程创建销毁开销)
掌握:
1.如何实例化
2.如何启动任务
3.如何向任务中传递数据
4.任务如何管理(取消 cts.Token.IsCancellationRequested/cts.Canecl())
5.任务等待
6.任务返回值((Task<T>泛型) )
7.分线程任务中如何捕获异常(处理分线程任务中的非法情况)
重点API及类总结:
1.实例化及启动
| 方法 | 特点 | 适用场景 | 线程池使用 |
|---|---|---|---|
new Task(() => {}).Start() | 手动控制启动时机,需显式调用 Start () | 需要延迟执行的任务 | 是(默认) |
Task.Run(() => {}) | 简化 API,自动启动任务 | 大多数异步操作场景 | 是 |
Task.Factory.StartNew(() => {}) | 支持丰富配置选项 | 需要定制任务行为(如长期运行) | 可选(可配置) |
2. 线程任务取消
| 类型 / 方法 | 作用 | 特点 | 使用场景 |
|---|---|---|---|
CancellationTokenSource | 提供取消令牌的源对象 | 可创建多个令牌,支持超时取消 | 所有需要取消机制的任务 |
CancellationToken | 取消请求的传递载体 | 轻量级结构,可安全传递 | 作为参数传递给任务 |
cts.Cancel() | 立即触发取消请求 | 同步触发取消 | 需要立即终止任务时 |
cts.CancelAfter(ms) | 延迟指定时间后取消 | 异步定时取消 | 需要超时控制的任务 |
token.IsCancellationRequested | 检查是否收到取消请求 | 非阻塞检查 | 任务内部定期检查 |
token.ThrowIfCancellationRequested() | 若取消则抛出异常 | 可触发异常处理流程 | 需要通过异常处理取消的场景 |
3. 线程任务等待
| 方法 | 作用 | 是否阻塞 | 返回值 |
|---|---|---|---|
task.Wait() | 等待单个任务完成 | 是 | 无 |
Task.WaitAny(tasks) | 等待任一任务完成 | 是 | 完成任务的索引 |
Task.WaitAll(tasks) | 等待所有任务完成 | 是 | 无 |
Task.WhenAny(tasks) | 等待任一任务完成 | 否 | 已完成的任务 |
Task.WhenAll(tasks) | 等待所有任务完成 | 否 | 包含所有结果的任务 |
factory.ContinueWhenAny(tasks, t => {}) | 任一任务完成后执行延续 | 否 | 延续任务 |
factory.ContinueWhenAll(tasks, ts => {}) | 所有任务完成后执行延续 | 否 | 延续任务 |
4. 线程任务返回值(Task<T>泛型应用)
| 用法 | 特点 | 获取结果方式 | 异常处理 |
|---|---|---|---|
Task<T>.Run(() => return T) | 异步计算并返回结果 | 可通过 await 或 Result 获取 | 异常包装在 AggregateException 中 |
await task<T> | 非阻塞获取结果 | 直接获取 T 类型结果 | 自动解包异常,可直接捕获 |
task<T>.Result | 阻塞获取结果 | 同步获取 T 类型结果 | 需捕获 AggregateException |
task<T>.GetAwaiter().GetResult() | 类似 Result 但直接抛出原始异常 | 同步获取 T 类型结果 | 直接抛出原始异常 |
Task.FromResult(T) | 创建已完成的带结果任务 | 立即获取预设结果 | 无异常(除非结果本身无效) |
Task的实例化方式
1.Task如何实例化(多种实例化方案)
- new Task()
- Task.Run();
- Task 工厂
1.new Task() 默认不会自动启动 需要手动Start启动 Action和Action<T>
namespace _1.Tesk
{
public partial class Form1 : Form
{
//CancellationTokenSource 主要用来像CancellationToken发一个信号,取消的信号
//怎么发信号?cts.Token能生成唯一的标识 将来cts.Cancel()发送取消信号
//每一个任务是一个分线程 cts.Token能生成唯一标识 将来cts.Cancel()取消任务的时候,
知道取消哪个任务
CancellationTokenSource cts = new CancellationTokenSource();
public Form1()
{
InitializeComponent();
}
Task t1 = null;
private void Form1_Load(object sender, EventArgs e)
{
//1.Task如何实例化(多种实例化方案)
//1.new Task() 默认不会自动启动 需要手动Start启动 Action和Action<T>
//public delegate void Action(); 委托
//public Task(Action action) 构造函数
t1 = new Task(new Action(() => { })); ;
t1 = new Task(() => { }); ;
t1 = new Task(DoWork); ;
//有一个取消的标识
t1 = new Task(DoWork, cts.Token);
//public delegate void Action<T>(); 委托
//t1 = new Task((obj) =>
//{
// Console.WriteLine(obj);
//});
1.2 Task.Run();静态方法创建任务实例 默认是自动启动 Action Func
Task.Run(new Func<string>(() => { return "Hello"; }));
Task.Run(() => { return "Hello"; });
Task.Run(new Func<int>(() => { return 123; }));
Task.Run(() => { return 123; });
Task.Run(new Func<Task>(() => { return new Task(() => { }); }));
Task.Run((() => { return new Task(() => { }); }));
Task.Run(new Func<Task<string>>(() => { return new Task<string>(() => { return "hello"; }); }));
Task.Run((() => { return new Task<string>(() => { return "hello"; }); }));
Task.Run(new Func<Task<int>>(() => { return new Task<int>(() => { return 123; }); }));
Task.Run((() => { return new Task<int>(() => { return 123; }); }));
Task.Run(new Func<Task<Task>>(() => { return new Task<Task>(() => { return new Task(() => { }); }); }));
//Task<T> 任务泛型 主要让任务能够返回结果
Task<int> tt1 = new Task<int>(() => { return 123; });
Task<string> tt2 = new Task<string>(() => { return "hello"; });
Task<Task> tt3 = new Task<Task>(() => { return new Task(() => { }); });
Task<Task<int>>tt4 = new Task<Task<int>>(() => { return new Task<int>(() => { return 1; }); });
1.3 Task 工厂
Task.Factory.StartNew(() => { });
Task.Factory.StartNew(() => { return 100; });
Task.Factory.StartNew(() => { return "hello"; });
Task.Factory.StartNew(() => { return new Task(() => { }); });
工厂方法 StartNew() 会直接创建并启动任务,简化代码。
不用实例化Task 在调用start了
asnyc和await是什么?
1. 核心原理
async/await 是基于 Task 的语法糖,允许以同步代码的形式编写异步逻辑,本质是状态机(编译器自动生成)的封装。
async:标记方法为异步方法,允许内部使用awaitawait:暂停当前方法执行,释放线程(不阻塞),待任务完成后恢复执行
异步编程是一种编程模式.C#中的异步线程可以通过Thread,ThreadPool,Task,async/await等来实现
多线程肯定是异步的,即多线程是异步也有可能出现在单线程的程序中.
2. 关键规则
- async关键字是一个方法修饰符,用它声明的方法,成为异步方法.
- await关键字用来等待一个Task或async方法完成,await关键字必须配合async关键字使用,不能单独应用await关键字.
- await只能用在async修饰的方法(即异步方法)内使用.
- await不会阻塞主线程.用户体验好.
3. 优势与最佳实践
优势
- 避免回调嵌套(“回调地狱”),代码可读性接近同步逻辑
- 非阻塞等待,提高 UI 线程响应性(如 WinForm/WPF)或服务器吞吐量(如ASP.NET)
最佳实践
- 优先返回
Task/Task<T>而非void(便于等待和异常处理) - 异步方法命名以
Async结尾(如GetDataAsync) - 避免
async void(仅用于事件处理) - 不要滥用
Task.Result/Task.Wait()(可能导致死锁,尤其在 UI 线程)
await能等待什么?
切记:await关键字不能等待同步代码,只能等待Task或异步方法,且异步方法必须有返回值
Task 与 async/await 的关系
async/await是 Task 的 “语法糖”,底层仍依赖 Task 实现- Task 可以独立使用(如
Task.Run),但async/await必须配合 Task - 同步方法中使用
Task.Result可能导致死锁,而await可避免此问题
asnync和await实现异步方法有什么好处?
- 即可以保证不阻塞,也可以保证异步执行的顺序
- 以同步代码的方式编写异步传输,让语法更加优美.
使用:

namespace _03_asnyc和await
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
SayHello1();
SayHello2();
SayHello3();
}
private void SayHello1()
{
Console.WriteLine("SayHello1");
}
private void SayHello2()
{
Console.WriteLine("SayHello2");
}
//异步方法
//在同步方法的前面添加一个async关键字 这个方法就会由原来的同步方法 变为异步方法
//虽然这个方法使用了async修饰符 但是如果方法体中没有await 还是同步方法
private async void SayHello3()
{
// await 等待异步执行的结果
// await 后面等待的必须是一个任务 Task Task<T>
Task task = new Task(() =>
{
Console.WriteLine("SayHello3");
});
task.Start();
await task;
await Task.Run(() =>
{
Console.WriteLine("另外一个任务");
});
}
private void button1_Click(object sender, EventArgs e)
{
SayHello3();
Console.WriteLine("后续代码后续代码");
}
private async void button2_Click(object sender, EventArgs e)
{
Task<int> t1=GetAsyncResult();
await t1;
Console.WriteLine(t1.Result+"-------");
}
private async Task<int> GetAsyncResult()
{
Task<int> t = Task.Run(() => {
Thread.Sleep(1000);
return 100;
});
int num = await t;
Console.WriteLine(num);
Console.WriteLine(t.Result);
return t.Result;
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button3_Click(object sender, EventArgs e)
{
GetAsyncResult2();
}
//异步方法的返回值必须 为 void 或者Task 或者 Task<T>
private async void GetAsyncResult2()
{
Task<int> t = Task.Run(() => {
Thread.Sleep(1000);
return 100;
});
int num= await t;
//Console.WriteLine(t.Result);
Console.WriteLine("获取值");
}
private async void button4_Click(object sender, EventArgs e)
{
//默认情况下 任务是无序的
//Task<string> t1 = new Task<string>(s =>
//{
// Console.WriteLine("任务1");
// return s.ToString() + "bbbb";
//}, "aaaa");
//t1.Start();
////参数prevTask 就是上一个任务 如果t1有结果,可以通过prevTask获取,如果没有 此参数就没有用
//Task t2 = t1.ContinueWith(prevTask =>
//{
// Console.WriteLine("任务2");
// Console.WriteLine(prevTask.Result);
//});
////参数2: 上一个任务 t2
////参数2: 当前任务的参数 200实参 num 形参
//Task t3 = t2.ContinueWith((prevTask, num) =>
//{
// Console.WriteLine("任务3");
// return (int)num;
//}, 200);
//Task t4 = t3.ContinueWith((prevTask) =>
//{
// Console.WriteLine("任务4");
// Console.WriteLine(prevTask.Result);
//});
Console.WriteLine("------------------------");
Task<string> t1 = new Task<string>(s =>
{
Console.WriteLine("任务1");
return s.ToString() + "bbbb";
}, "aaaa");
t1.Start();
await t1;
Task t2 = Task.Run(() => {
Console.WriteLine("任务2");
});
await t2;
Task<int> t3 = new Task<int>(num =>
{
Console.WriteLine("任务3");
return (int)num;
},200);
t3.Start();
await t3;
Task t4 = Task.Run(() => {
Console.WriteLine("任务4");
Console.WriteLine(t3.Result);
});
}
}
}
对上面每段代码的 拆分解释 含义:
构造函数中的使用

-
SayHello1和SayHello2是普通同步方法 -
SayHello3是异步方法,但在构造函数中调用时没有await,所以实际上是同步执行
同步方法展示

这个方法展示了最基本的同步执行方法,代码按顺序一行一行执行.
异步方法基础示例

这里展示了:
1.手动创建和启动Task
2.使用await等待任务完成
3.使用Task.Run简化任务创建
按钮点击事件中的异步调用

这里演示了不等待异步方法完成的后果:"后续代码"会立即执行,而不会等待SayHello3完成。
带返回值的异步方法

这段代码展示了:
-
如何定义返回值的异步方法(
Task<T>) -
两种获取结果的方式:
await和.Result -
在UI事件处理中使用async void的合理场景
任务延续(Continuation)示例

这段代码展示了:
-
使用
await实现顺序异步操作 -
每个任务完成后才执行下一个
-
可以访问前序任务的结果
扩展:
线程池、Task任务、async异步方法 C#多线程深入解析与实战-CSDN博客 C#中的多线程和异步编程详解 - Jack-sparrow - 博客园 https://www.toutiao.com/article/7137485547618288169 https://www.toutiao.com/article/7255526505097347599 C#Task详解_C#Task用法介绍-C#.Net教程-PHP中文网
Task任务: C# Task详解 - 五维思考 - 博客园 C# Task详解 - 漫思 - 博客园 C# Task任务详细讲解-CSDN博客 C# Task详解 - yinjun98 - 博客园
async和await: 深入解析C#中的async和await关键字_C#教程_脚本之家 使用 Async 和 Await 的任务异步编程 (TAP) 模型 - C# | Microsoft Learn https://devblogs.microsoft.com/dotnet-ch/async-await在-c语言中是如何工作的/
异步编程模型变迁: 谈谈c#中异步编程模型的变迁_c# 异步编程模型进化-CSDN博客 C# 实现异步编程的几种方式_c# 异步方法-CSDN博客

1033

被折叠的 条评论
为什么被折叠?



