news 2026/7/13 15:47:00

C# Task WaitAll、WaitAny、WhenAll、WhenAny

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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"); } } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/13 15:45:32

nabla.nvim插件开发指南:如何为项目贡献新的数学符号支持

nabla.nvim插件开发指南&#xff1a;如何为项目贡献新的数学符号支持 【免费下载链接】nabla.nvim take your scientific notes :pencil2: in Neovim 项目地址: https://gitcode.com/gh_mirrors/na/nabla.nvim nabla.nvim是一款专为Neovim设计的科学笔记插件&#xff0c…

作者头像 李华
网站建设 2026/7/13 15:44:50

NLP核心技术实践之(四)命名实体识别与关系抽取的端到端应用

1. 命名实体识别与关系抽取的技术全景命名实体识别&#xff08;NER&#xff09;和关系抽取&#xff08;RE&#xff09;就像自然语言处理领域的"黄金搭档"——一个负责找出文本中的关键元素&#xff0c;另一个则揭示这些元素之间的联系。想象一下&#xff0c;当你在阅…

作者头像 李华
网站建设 2026/7/13 15:42:56

SGM 代价聚合:4路径与8路径性能对比,P1/P2惩罚项调参实战

SGM代价聚合&#xff1a;4路径与8路径性能对比及P1/P2惩罚项调参实战 1. SGM代价聚合的核心原理与路径选择策略 立体匹配中的半全局匹配&#xff08;SGM&#xff09;算法之所以能在精度和效率之间取得平衡&#xff0c;关键在于其独特的代价聚合机制。与传统局部算法不同&#…

作者头像 李华
网站建设 2026/7/13 15:39:41

让qoder操作doc的步骤

ai-提效部分 由于这个要写各种文档 于是&#xff0c;我想了一下 ai既然可以帮忙操作文件夹下的代码文件 应该也可以操作wps软件的doc文档 首先理解doc文件&#xff0c;在wps里面提供的机制 对doc文件&#xff0c;可以被wps文件怎么操作 这个操作的机制是什么 机制体系是什么 了…

作者头像 李华
网站建设 2026/7/13 15:38:17

AI+港口智慧物流:集装箱调度+船舶预测+堆场优化

AI港口智慧物流&#xff1a;集装箱调度船舶预测堆场优化 引言 全球90%的贸易货物通过海运运输&#xff0c;港口是全球供应链的关键节点。一个大型港口每天处理数万个集装箱&#xff0c;但传统港口调度依赖人工经验&#xff0c;船舶等待时间长、堆场翻箱率高、集卡空驶严重。 AI…

作者头像 李华