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");
        }
    }
}
相关推荐
兰令水1 小时前
hot100【acm版】【2026.7.11/12打卡-java版本】
java·开发语言·数据结构·算法·职场和发展
从零开始的代码生活_1 小时前
C++ string 详解:常用接口、字符串算法与深拷贝实现
开发语言·c++·后端·学习·算法
m0_738120722 小时前
PHP代码审计基础——面向对象(四)
android·开发语言·网络·安全·github·php
2601_963771372 小时前
10 Best PHP Media CMS and Scripts for Web Creators in 2026
开发语言·前端·php
阿里嘎多学长2 小时前
2026-07-09 GitHub 热点项目精选
开发语言·程序员·github·代码托管
带娃的IT创业者2 小时前
监控并非安全:当隐私成为技术的祭品
java·开发语言·安全·数据安全·监控·隐私保护·加密技术
玖玥拾3 小时前
C# 语言进阶(十四)Unity UI界面开发 + 网络消息联动
服务器·开发语言·网络·ui·unity·c#·游戏引擎
aaPIXa6223 小时前
C++ 质量前置检查:clang-format 与 clang-tidy 实践指南
开发语言·c++
余额瞒着我当琳3 小时前
C++ 基础核心概念精讲:引用、内联与 nullptr
java·开发语言·c++