C# Task WaitAll、WaitAny、WhenAll、WhenAny 笔记承接承接Task获取异步结果笔记本节课核心四大方法WaitAll、WaitAny、WhenAll、WhenAny核心区分带Wait开头同步阻塞带When开头异步非阻塞搭配任务工厂回调补齐限时等待用法窗体控件Button1~Button4分别对应4组对比案例二、前置基础概念2.1 TaskFactory 任务工厂作用批量创建、调度、管理大批量异步任务factory.StartNew()工厂创建并自动启动任务等价 Task.Run()优势批量管理任务、自带完成回调方法适合多任务并发场景2.2 死循环代码作用案例中第三个任务编写while(true)死循环永久不会执行完毕用来测试多任务等待效果2.3 方法总分类考试必考✅ 同步阻塞方法Task.WaitAll()、Task.WaitAny()→ 卡死UI✅ 异步非阻塞方法Task.WhenAll()、Task.WhenAny()→ 不卡死UI三、案例1同步阻塞 WaitAll WaitAnyButton13.1 核心原理Task.WaitAll()同步等待必须等待集合内所有任务全部执行完毕才执行后续代码Task.WaitAny()同步等待只要集合内任意一个任务执行完毕立刻放行执行后续代码共性两个都是同步方法执行时阻塞主线程直接卡死窗体3.2 逐行拆分带注释代码private void button1_Click(object sender, EventArgs e) { //1.实例化任务工厂 TaskFactory factory new TaskFactory(); //2.创建任务集合批量存储异步任务 ListTask list new ListTask(); //3.批量添加并发任务 list.Add(factory.StartNew(() { Console.WriteLine(查询数据库); })); list.Add(factory.StartNew(() { Console.WriteLine(查询缓存); })); //第三个任务死循环永久无法执行完毕 list.Add(factory.StartNew(() { while (true) { } Console.WriteLine(查询接口); })); //两组代码二选一测试 //Task.WaitAll(list.ToArray()); //同步阻塞需要等待3个任务全部完成第三个死循环永久卡死代码永不向下执行 Task.WaitAny(list.ToArray()); //同步阻塞只要任意一个任务执行完毕直接放行 //数据库/缓存任务率先执行完毕直接打印末尾日志不会卡死 Console.WriteLine(所有的操作执行完了); }3.3 运行现象开启WaitAll程序直接卡死控制台不打印末尾文字开启WaitAny瞬间放行打印日志但是依旧阻塞UI四、案例2异步非阻塞 WhenAll WhenAnyButton24.1 核心原理WhenAll、WhenAny纯异步方法不会阻塞主线程窗体永不卡死返回值返回Task任务必须搭配ContinueWith接收回调结果和Wait方法功能一模一样唯一区别是否阻塞UI4.2 代码拆分注释private void button2_Click(object sender, EventArgs e) { TaskFactory factory new TaskFactory(); ListTask list new ListTask(); list.Add(factory.StartNew(() { Console.WriteLine(查询数据库); })); list.Add(factory.StartNew(() { Console.WriteLine(查询缓存); })); list.Add(factory.StartNew(() { while (true) { } Console.WriteLine(查询接口); })); //两组代码二选一测试 //WhenAll全部任务执行完毕后触发回调异步不阻塞 //Task.WhenAll(list.ToArray()).ContinueWith(t //{ // Console.WriteLine(所有的操作执行完了); //}); //WhenAny任意一个任务执行完毕触发回调 Task.WhenAny(list.ToArray()).ContinueWith(t { Console.WriteLine(至少一个异步操作执行完了); }); }4.3 同步VS异步对比必考WaitAll / WaitAny同步阻塞卡住UI简单粗暴项目禁用WhenAll / WhenAny异步回调不卡UI搭配ContinueWith开发首选五、案例3任务工厂自带回调 ContinueWhenButton35.1 方法释义TaskFactory内置专属回调方法简化WhenContinueWith写法等价封装ContinueWhenAll WhenAll ContinueWith 封装版ContinueWhenAny WhenAny ContinueWith 封装版5.2 拆分代码private void button3_Click(object sender, EventArgs e) { TaskFactory factory new TaskFactory(); ListTask list new ListTask(); list.Add(factory.StartNew(() { Console.WriteLine(查询数据库); })); list.Add(factory.StartNew(() { Console.WriteLine(查询缓存); })); list.Add(factory.StartNew(() { while (true) { } Console.WriteLine(查询接口); })); //全部任务完成回调 //factory.ContinueWhenAll(list.ToArray(), (t) //{ // Console.WriteLine(所有的操作都执行完了); //}); //任意一个任务完成回调本案例执行 factory.ContinueWhenAny(list.ToArray(), (t) { Console.WriteLine(至少一个操作执行完了); }); }5.3 使用场景批量创建任务、统一调度场景优先使用任务工厂自带回调代码更加简洁六、案例4任务限时等待 Wait(毫秒)Button46.1 方法作用任务对象.Wait(int millisecondsTimeout)限时阻塞等待作用等待当前单个任务执行设置最大等待时长任务提前执行完毕立刻放行任务超时未执行完毕放弃等待直接放行6.2 逐行解析private void button4_Click(object sender, EventArgs e) { Task t1 new Task(() { Console.WriteLine(的函数点击发送); }); t1.Start(); //限时等待1000毫秒最多阻塞1秒 t1.Wait(1000); Console.WriteLine(sassss); }6.3 拓展辨析t1.Wait()无参永久等待任务完成无限阻塞t1.Wait(1000)有参限时等待超时自动放行七、四大方法超级对照表背诵版方法名称同步/异步执行规则是否阻塞UITask.WaitAll同步等待全部任务完成✅ 阻塞Task.WaitAny同步等待任意一个任务完成✅ 阻塞Task.WhenAll异步等待全部任务完成❌ 不阻塞Task.WhenAny异步等待任意一个任务完成❌ 不阻塞八、易错考点汇总带Wait全部是同步、阻塞带When全部是异步、非阻塞秒杀选择题When系列方法必须配合ContinueWith接收结果不能直接写后续业务ContinueWhenAll、ContinueWhenAny When封装版任务工厂专属Wait()无参永久阻塞传入毫秒实现限时等待存在死循环任务WaitAll永久卡死WaitAny正常放行九、完整版可运行代码using System; using System.Collections.Generic; using System.Threading.Tasks; using System.Windows.Forms; namespace _6waitAny和waitall_whena { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { TaskFactory factory new TaskFactory(); ListTask list new ListTask(); list.Add(factory.StartNew(() { Console.WriteLine(查询数据库); })); list.Add(factory.StartNew(() { Console.WriteLine(查询缓存); })); list.Add(factory.StartNew(() { while (true) { } Console.WriteLine(查询接口); })); //Task.WaitAll(list.ToArray()); Task.WaitAny(list.ToArray()); Console.WriteLine(所有的操作执行完了); } private void button2_Click(object sender, EventArgs e) { TaskFactory factory new TaskFactory(); ListTask list new ListTask(); list.Add(factory.StartNew(() { Console.WriteLine(查询数据库); })); list.Add(factory.StartNew(() { Console.WriteLine(查询缓存); })); list.Add(factory.StartNew(() { while (true) { } Console.WriteLine(查询接口); })); //Task.WhenAll(list.ToArray()).ContinueWith(t //{ // Console.WriteLine(所有的操作执行完了); //}); Task.WhenAny(list.ToArray()).ContinueWith(t { Console.WriteLine(至少一个异步操作执行完了); }); } private void button3_Click(object sender, EventArgs e) { TaskFactory factory new TaskFactory(); ListTask list new ListTask(); list.Add(factory.StartNew(() { Console.WriteLine(查询数据库); })); list.Add(factory.StartNew(() { Console.WriteLine(查询缓存); })); list.Add(factory.StartNew(() { while (true) { } Console.WriteLine(查询接口); })); //factory.ContinueWhenAll(list.ToArray(), (t) //{ // Console.WriteLine(所有的操作都执行完了); //}); factory.ContinueWhenAny(list.ToArray(), (t) { Console.WriteLine(至少一个操作执行完了); }); } private void button4_Click(object sender, EventArgs e) { Task t1 new Task(() { Console.WriteLine(的函数点击发送); }); t1.Start(); t1.Wait(1000); Console.WriteLine(sassss); } } }