当前位置: 首页 > news >正文

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 & WaitAny(Button1)

3.1 核心原理

  • Task.WaitAll():同步等待,必须等待集合内所有任务全部执行完毕,才执行后续代码

  • Task.WaitAny():同步等待,只要集合内任意一个任务执行完毕,立刻放行执行后续代码

  • 共性:两个都是同步方法,执行时阻塞主线程,直接卡死窗体

3.2 逐行拆分带注释代码

private void button1_Click(object sender, EventArgs e) { //1.实例化任务工厂 TaskFactory factory = new TaskFactory(); //2.创建任务集合,批量存储异步任务 List<Task> list = new List<Task>(); //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 运行现象

  1. 开启WaitAll:程序直接卡死,控制台不打印末尾文字

  2. 开启WaitAny:瞬间放行,打印日志,但是依旧阻塞UI

四、案例2:异步非阻塞 WhenAll & WhenAny(Button2)

4.1 核心原理

  • WhenAll、WhenAny:纯异步方法,不会阻塞主线程,窗体永不卡死

  • 返回值:返回Task任务,必须搭配ContinueWith接收回调结果

  • 和Wait方法功能一模一样,唯一区别:是否阻塞UI

4.2 代码拆分注释

private void button2_Click(object sender, EventArgs e) { TaskFactory factory = new TaskFactory(); List<Task> list = new List<Task>(); 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:任务工厂自带回调 ContinueWhen(Button3)

5.1 方法释义

TaskFactory内置专属回调方法,简化When+ContinueWith写法,等价封装:

  • ContinueWhenAll= WhenAll + ContinueWith 封装版

  • ContinueWhenAny= WhenAny + ContinueWith 封装版

5.2 拆分代码

private void button3_Click(object sender, EventArgs e) { TaskFactory factory = new TaskFactory(); List<Task> list = new List<Task>(); 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(毫秒)(Button4)

6.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):有参,限时等待,超时自动放行

七、四大方法超级对照表(背诵版)

方法名称

同步/异步

执行规则

是否阻塞UI

Task.WaitAll

同步

等待全部任务完成

✅ 阻塞

Task.WaitAny

同步

等待任意一个任务完成

✅ 阻塞

Task.WhenAll

异步

等待全部任务完成

❌ 不阻塞

Task.WhenAny

异步

等待任意一个任务完成

❌ 不阻塞

八、易错考点汇总

  1. Wait全部是同步、阻塞;带When全部是异步、非阻塞(秒杀选择题)

  2. When系列方法必须配合ContinueWith接收结果,不能直接写后续业务

  3. ContinueWhenAll、ContinueWhenAny = When封装版,任务工厂专属

  4. Wait()无参永久阻塞,传入毫秒实现限时等待

  5. 存在死循环任务: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(); List<Task> list = new List<Task>(); 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(); List<Task> list = new List<Task>(); 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(); List<Task> list = new List<Task>(); 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"); } } }
http://www.cnnetsun.cn/news/3346044.html

相关文章:

  • nabla.nvim插件开发指南:如何为项目贡献新的数学符号支持
  • NLP核心技术实践之(四)命名实体识别与关系抽取的端到端应用
  • 革命性AI视频生成工具AnyFlow-FAR-Wan2.1-1.3B-Diffusers:NVIDIA推出的任意步数视频扩散模型完全指南
  • SGM 代价聚合:4路径与8路径性能对比,P1/P2惩罚项调参实战
  • 让qoder操作doc的步骤
  • AI+港口智慧物流:集装箱调度+船舶预测+堆场优化
  • 如何在AMD NPU上部署Llama-2-7b-hf_rai_1.7.1_npu_4K:完整新手教程
  • AI+危险品运输:全程监控+应急响应+合规管理
  • AI+供应链韧性:风险预测+应急调度+弹性优化
  • gemma-4-e4b-it-OptiQ-4bit的部署优化:内存管理、批处理和性能调优最佳实践
  • 21天学pcie--Linux 下查看 BAR:lspci -vv(实战必会)
  • ChatGPT生成抖音脚本不火?问题不在模型,在于你漏掉了这4个关键元数据注入节点
  • 终极指南:如何免费解锁Wand-Enhancer的所有高级游戏修改功能
  • 一个爬虫项目改成 AI 流程后,最难的部分完全变了
  • 如何快速上手AnyFlow-FAR-Wan2.1-1.3B-Diffusers:5分钟搭建文本到视频生成环境
  • RoCEv2 网络的完整协议栈简介
  • Qwen2.5-7B-Instruct_rai_1.7.1_npu_4K:AMD Ryzen AI上的高效大语言模型部署指南
  • 如何用Gotalk实现分布式系统负载均衡:心跳机制详解
  • NVIDIA-Nemotron-3-Nano-4B-OptiQ-4bit:Apple Silicon专属的革命性混合架构大模型来了!
  • 从投诉率骤升23%到NPS提升18分,我们如何用反馈聚类+情感时序建模重构产品决策链,
  • 别再写for循环了:2024最前沿的向量化AI分析法——用PyTorch+Polars实现毫秒级特征生成(含GPU加速实测对比数据)
  • 解密Enigma虚拟打包文件:evbunpack实战指南
  • 【技术实践】上海交通大学学位论文本地化保存与自动化抓取方案解析
  • AI绘图实战:蜡笔风个人主页海报提示词拆解
  • shell,Linux用户和工作组,以及Linux文件系统·权限
  • 中小企业出海行动推进:全球市场研究网络赋能精准洞察与高效供应商对接
  • DAKeyboardControl:iOS键盘交互的革命性解决方案 - 一行代码实现iMessages式滑动关闭
  • TeleStyleV2-Qwen-Image-Edit-2511-bf16:革命性图像风格迁移模型,4步实现专业级内容保留编辑 [特殊字符]
  • Ornith-1.0-9B-6bit常见问题解答:解决10个最常遇到的运行问题
  • 高德地图 Web 服务 API V3 公交线路爬取:Python 脚本 5 分钟获取 1000 条线路坐标