
笔记承接承接Task全套笔记是多线程最后一节核心语法AsyncAwait是C#语法糖简化异步代码、解决回调地狱是目前异步编程最优写法前置学习链路Thread原生线程→ThreadPool线程池→Task异步任务→async/await语法窗体控件button1~button4分别测试异步执行、返回值、串行任务二、async与await基础语法必考2.1 两个关键字作用async修饰方法标识该方法为异步方法单独使用无任何异步效果必须配合awaitawait等待异步任务仅能写在async方法内部后面只能绑定 Task / 异步方法2.2 核心底层特性背诵await等待任务执行期间不会阻塞UI主线程让出主线程权限主线程可以继续执行其他业务异步任务执行完毕自动切回原线程继续执行await后续代码最大优势同步式代码写法实现异步编程效果代码工整规避ContinueWith多层回调混乱2.3 异步方法返回值规范void事件点击方法专用按钮点击Task无返回值异步方法TaskT带返回值异步方法T为返回数据类型三、基础同步异步方法拆分3.1 普通同步方法SayHello1、SayHello2普通同步方法代码自上而下串行执行执行完毕才执行下一行public void SayHello1() { Console.WriteLine(hello world1); } public void SayHello2() { Console.WriteLine(hello world2); }3.2 基础异步方法 SayHello3逐行拆解执行流程修正原代码模糊注释//异步方法async修饰不能单独生效 public async void SayHello3() { //1.同步代码立即执行 Console.WriteLine(dddddddddddddddddddddddddd); //2.创建并启动原生Task任务 Task t new Task(() { Console.WriteLine(hello world3); }); t.Start(); //3.异步等待让出主线程不阻塞UI //后台等待t执行完毕主线程释放可以执行其他操作 await t; //4.第一个任务完成执行第二个异步任务 await Task.Run(() { Console.WriteLine(另一个任务); }); }3.3 窗体构造方法执行顺序public Form1() { InitializeComponent(); SayHello1();//同步执行 SayHello2();//同步执行 SayHello3();//调用异步方法遇到await立刻让出主线程不阻塞构造函数 Console.WriteLine(sssssssssssss);//该行无需等待异步完成直接执行 }输出顺序hello1→hello2→dddd→sssss→hello3→另一个任务四、四大按钮案例逐行解析4.1 button1异步调用基础测试private void button1_Click(object sender, EventArgs e) { SayHello3();//调用异步方法 //无需等待异步执行完毕直接执行后续代码 Console.WriteLine(后续执行的代码); }执行特点异步代码后台运行主线程直接放行互不阻塞4.2 button2获取带返回值异步结果核心await自动解析泛型Task结果替代.Result不会阻塞线程private async void button2_Click(object sender, EventArgs e) { Taskint t1 GetResult();//调用异步方法 await t1;//等待任务执行不阻塞UI Console.WriteLine(t1.Resultssssssssssssssss); } /// summary /// 有返回值异步业务方法 /// 返回值必须声明 Task基础类型 /// /summary public async Taskint GetResult() { //启动耗时异步任务 Taskint t Task.Run(() { return 100; }); //✅await自动提取任务返回值赋值变量最优写法 int num await t; //两种取值等价await取值 / Result取值 Console.WriteLine(numsss); Console.WriteLine(t.Result); return t.Result; }4.3 button3最简取值案例简化冗余代码直观展示await取值原理private async void button3_Click(object sender, EventArgs e) { //模拟耗时异步任务 Taskint t Task.Run(() { Thread.Sleep(100); return 100; }); //await阻塞异步流程不阻塞UI主线程 int num await t; //两种方式获取返回值结果完全一致 Console.WriteLine(num); Console.WriteLine(t.Result); }4.4 button4异步任务串行顺序执行对比旧写法ContinueWith链式回调新版await串行执行代码极简、可读性极高private async void button4_Click(object sender, EventArgs e) { #region 老旧写法ContinueWith链式回调多层嵌套、代码混乱回调地狱 //Taskstring t1 new Taskstring((s) //{ // Console.WriteLine(任务1); // return t1s; //},aaaa); //t1.Start(); //Task t2 t1.ContinueWith(preTask //{ // Console.WriteLine(任务2); // Console.WriteLine(preTask.Result); //}); //Task t3 t2.ContinueWith(preTask //{ // Console.WriteLine(任务3); //}); #endregion //✅新式await串行写法自上而下顺序执行逻辑清晰 Taskstring t1 new Taskstring((s) { Console.WriteLine(任务1); return t1 s; }, aaaa); t1.Start(); string s1 await t1;//等待任务1执行完毕 Task t2 Task.Run(() { Console.WriteLine(任务2); }); await t2;//等待任务2执行完毕 Task t3 Task.Run(() { Console.WriteLine(任务3); }); await t3;//等待任务3执行完毕 }五、异步五层演进期末简答题必考Thread原生线程粒度最低手动创建销毁开销大无法管控返回值极易内存泄漏ThreadPool线程池复用线程、优化性能无法管控任务状态、获取返回值Task异步任务基于线程池封装自带状态、返回值需要ContinueWith回调代码嵌套混乱asyncawait语法糖同步代码结构实现异步逻辑解决回调地狱不阻塞UI最终演进方向Thread → ThreadPool → Task → Async/Await六、易错考点汇总单独添加async没有await没有任何异步效果依旧同步执行await只能写在async修饰的方法内部普通方法禁止使用awaitawait后方只能放置 Task、TaskT、异步方法不能写普通变量Result取值阻塞主线程await取值不阻塞UI优先使用await按钮点击事件异步返回值只能写void业务异步方法禁止写void必须返回Task七、整理完整版可运行代码using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace _3async和await { public partial class Form1 : Form { public Form1() { InitializeComponent(); SayHello1(); SayHello2(); SayHello3(); Console.WriteLine(sssssssssssss); } public void SayHello1() { Console.WriteLine(hello world1); } public void SayHello2() { Console.WriteLine(hello world2); } //可以在方法前添加async关键字 使其变成异步的方法 //如果仅仅添加async 没有异步的效果 配合await进行使用 //await是等待,后面只能跟Task或者异步方法等待异步任务执行时候再会执行到主线程里面 //async awai最大特点既有异步的特性不会阻塞使用同步代码编写方式去实现异步编程 结构更清晰 public async void SayHello3() { Console.WriteLine(dddddddddddddddddddddddddd); Task t new Task(() { Console.WriteLine(hello world3); }); t.Start(); await t;// 等待异步任务执行在等待的过程中不会阻塞主线程回到主线程去执行 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) { Taskint t1 GetResult(); await t1; Console.WriteLine(t1.Resultssssssssssssssss); } //返回值是 Taskint类型 public async Taskint GetResult() { // 有返回值的异步任务 Taskint t Task.Run(() { return 100; }); int num await t; //等待异步任务执行把结果取出来 Console.WriteLine(numsss); Console.WriteLine(t.Result); return t.Result; } private async void button3_Click(object sender, EventArgs e) { // 有返回值的异步任务 Taskint t Task.Run(() { Thread.Sleep(100); return 100; }); int num await t; //等待异步任务执行把结果取出来 Console.WriteLine(num); Console.WriteLine(t.Result); } private async void button4_Click(object sender, EventArgs e) { /* //异步任务按照顺序执行 Taskstring t1 new Taskstring((s) { Console.WriteLine(任务1); return t1s; },aaaa); t1.Start(); //preTask 上一个任务 t1 Task t2 t1.ContinueWith(preTask { Console.WriteLine(任务2); Console.WriteLine(preTask.Result); }); // t3在t2执行之后执行 Task t3 t2.ContinueWith(preTask { Console.WriteLine(任务3); }); */ Taskstring t1 new Taskstring((s) { Console.WriteLine(任务1); return t1 s; }, aaaa); t1.Start(); string s1 await t1; Task t2 Task.Run(() { Console.WriteLine(任务2); }); await t2; Task t3 Task.Run(() { Console.WriteLine(任务3); }); await t3; } } } /* * thread * * threadPool * * Task 和 TaskT * * Async和Await * * * */AsyncTask实现斐波那契数列渲染案例笔记承接承接async/await语法、Task进度条案例综合大题实操案例整合知识点异步语法、取消令牌、递归算法、DataGridView表格渲染、进度条联动、暂停/继续/重置窗体控件Button1启动、Button2暂停、Button3继续、Button4停止、ProgressBar进度条、DataGridView表格二、全局变量逐句释义四个全局变量管控任务、状态、计数全部为联动启停核心namespace _4例子 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } //全局异步任务管控斐波那契计算任务 Task task; //暂停标记false运行、true暂停 bool pause false; //取消令牌安全管控task任务 CancellationTokenSource cts; //强制停止标记清空表格、归零进度 bool stop false; //全局计数器控制计算1~50位斐波那契数列 int i 0;三、核心入口启动按钮 button13.1 方法特征添加async修饰内部可以使用await外层while循环控制整体流程实现有序串行计算private async void button1_Click(object sender, EventArgs e) { //启动初始化清空暂停、停止状态 pause false; stop false; //循环判定三大条件 //1.不暂停 2.不强制停止 3.计算位数小于等于50 while (!pause !stop i 50) { //await等待每一位斐波那契计算完成不阻塞UI //拆分计算UI刷新异步任务 await Calc(i); //计算完成位数自增 i; } }3.2 执行逻辑循环每遍历一次计算1位斐波那契数列await Calc(i)等待单次计算页面渲染完毕再执行下一次循环全程不卡死窗体同步写法实现异步效果四、业务封装方法Calc 计算UI渲染功能创建Task异步任务、绑定取消令牌、执行斐波那契计算、刷新进度条表格/// summary /// 异步封装方法计算斐波那契 刷新UI /// 返回值Task 支持上层await等待 /// /summary public Task Calc(int data) { //每一次计算重新生成取消通行证禁止复用旧令牌 cts new CancellationTokenSource(); //实例化异步任务第二个参数data→向任务传参 task new Task(s { //取出当前计算的位数 long num Convert.ToInt64(s); //调用递归算法计算斐波那契结果 long result FiBo(num); try { //跨线程刷新UI子线程禁止直接操作控件必须Invoke Invoke(new Action(() { //进度条联动位数×2放大进度填满0~100进度条 progressBar1.Value (int)num * 2; //表格插入数据第一列位数、第二列计算结果插入首行 dataGridView1.Rows.Insert(0, new object[] { num, result }); //触发强制停止清空所有页面状态、复位计数 if (stop) { i 0; progressBar1.Value 0; dataGridView1.Rows.Clear(); } })); } catch (Exception) { //捕获UI销毁、线程冲突异常防止程序闪退 Console.WriteLine(UI渲染异常); } }, data, cts.Token);//传入参数绑定取消令牌 task.Start();//启动异步任务 return task;//返回任务供上层await接收 }五、递归算法斐波那契 FiBo5.1 算法规则斐波那契数列规则第1位、第2位数值 1后续每一位 前两位之和/// summary /// 递归实现斐波那契数列 /// /summary public long FiBo(long n) { //递归终止条件第一位、第二位直接返回1 if (n 3) { return 1; } //递归公式前一项前二项 return FiBo(n - 1) FiBo(n - 2); }5.2 课堂易错点n50递归计算量爆炸运算极慢CPU占用飙升使用long返回值int范围太小高位斐波那契数值溢出报错六、三大功能按钮解析6.1 Button2 暂停private void button2_Click(object sender, EventArgs e) { pause true;//开启暂停标记阻塞外层while循环 }6.2 Button3 继续修复原生逻辑隐患原生代码逻辑直接调用button1_Click不会重置循环但是保留原有进度继续执行缺陷极端情况产生冗余任务private void button3_Click(object sender, EventArgs e) { pause false;//关闭暂停标记放行循环 //重启触发异步循环接续原有进度执行 button1_Click(null, null); }6.3 Button4 强制停止复位private void button4_Click(object sender, EventArgs e) { stop true;//开启全局停止标记 i 0;//计数器归零 progressBar1.Value 0;//清空进度条 dataGridView1.Rows.Clear();//清空表格数据 }七、原生代码Bug汇总考试改错考点递归性能漏洞第40位之后递归计算巨慢界面卡顿递归深度过高取消令牌闲置声明cts但是未调用Cancel停止任务无法销毁后台线程轻微内存泄漏继续按钮重启任务存在极小概率任务叠加未做窗体关闭资源释放后台递归常驻进程八、整体执行流程背诵版点击启动初始化状态进入while循环循环调用Calc创建异步Task绑定取消令牌后台递归计算斐波那契数列Invoke刷新进度条表格await等待单次任务结束计数器自增执行下一轮计算点击暂停pausetrue阻断循环暂停运算点击继续关闭暂停标记接续进度运算点击停止全局复位清空页面、归零计数九、核心综合考点异步嵌套async外层接收等待Task内层执行业务UI跨线程更新所有控件赋值必须包裹Invoke状态分流pause控制暂停、stop强制全局复位双层状态管控算法异步结合递归耗时业务必须放入子线程防止UI卡死十.完整代码using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace _4例子 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } Task task; bool pause false; CancellationTokenSource cts; bool stop false; int i 0; private async void button1_Click(object sender, EventArgs e) { pause false; stop false; while (!pause!stopi50) { //计算斐波那契 和更新进度一个异步函数 await Calc(i); i; } } //data i s public Task Calc(int data) { cts new CancellationTokenSource(); task new Task(s { //先取出计算第几位的斐波那契数 long num Convert.ToInt64(s); long result FiBo(num); try { Invoke(new Action(() { progressBar1.Value (int)num * 2; dataGridView1.Rows.Insert(0, new object[] { num, result });//添加行 num 第一列值,result 第二列值 if (stop) { i 0; progressBar1.Value 0; dataGridView1.Rows.Clear(); } })); } catch (Exception) { Console.WriteLine(); } //更新表格更新进度 },data,cts.Token); task.Start(); return task; } //封装斐波那契函数的功能 public long FiBo(long n) { if (n3) { return 1; } return FiBo(n - 1) FiBo(n - 2); } private void button2_Click(object sender, EventArgs e) { pause true; } private void button3_Click(object sender, EventArgs e) { pause false; button1_Click(null, null); } private void button4_Click(object sender, EventArgs e) { stop true; //cts.Cancel(); i 0; progressBar1.Value 0; dataGridView1.Rows.Clear(); } } }