C# Task.WaitAll 的用法

目录

简介

1.WaitAll(Task[], Int32, CancellationToken)

2.WaitAll(Task[])

3.WaitAll(Task[], Int32)

4.WaitAll(Task[], CancellationToken)

5.WaitAll(Task[], TimeSpan)

结束


简介

Task.WaitAll 是 C# 中用于并行编程的一个的方法,它属于 System.Threading.Tasks 命名空间。主要作用是等待提供的所有 Task 对象完成其执行过程。通过使用 Task.WaitAll,开发者可以确保一组并行执行的任务全部完成后,再继续执行后续的代码。这对于需要等待多个异步操作同时完成以继续执行其他操作的场景非常有用。

Task.WaitAll 方法有多个重载版本,以适应不同的需求。最基本的版本接收一个 Task 对象的数组作为参数,并等待这个数组中的所有任务完成。如果所有任务都成功完成,则该方法正常返回;如果有任何任务在执行过程中抛出了异常,这些异常会被封装在 AggregateException 中并抛出。如果任务被取消,AggregateException 的 InnerExceptions 集合中会包含 OperationCanceledException。

Task.WaitAll 还提供了带有超时和取消令牌的重载方法,允许开发者在指定的时间间隔内等待所有任务完成,或者如果等待被取消,则提前退出等待。这些重载版本为处理超时和取消操作提供了更灵活的方式。

Task.WaitAll 方法适用于多种场景,如同时处理多个数据库查询、同时下载多个文件或执行任何需要并行处理的任务集合。通过并行处理,可以显著提高应用程序的响应速度和吞

打开你的项目,利用 Visual Studio 2022 反编译功能看看当前的 WaitAll 是那个对应的版本,比如下图,我用的是 .NetFramework 4.8 

官方文档:点击跳转

定义
命名空间:
System.Threading.Tasks
程序集:
System.Runtime.dll
等待提供的所有 Task 对象完成执行过程。

WaitAll(Task[], Int32, CancellationToken)等待提供的所有 Task 对象在指定的毫秒数内完成执行,或等到取消等待
WaitAll(Task[])等待提供的所有 Task 对象完成执行过程。
WaitAll(Task[], Int32)等待所有提供的 Task 在指定的毫秒数内完成执行
WaitAll(Task[], CancellationToken)等待提供的所有 Task 对象完成执行过程(除非取消等待)
WaitAll(Task[], TimeSpan)等待所有提供的可取消 Task 对象在指定的时间间隔内完成执行

1.WaitAll(Task[], Int32, CancellationToken)

等待提供的所有 Task 对象在指定的毫秒数内完成执行,或等到取消等待。

[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
public static bool WaitAll (System.Threading.Tasks.Task[] tasks, int millisecondsTimeout, System.Threading.CancellationToken cancellationToken);

参数
tasks  Task[]
要等待的 Task 实例的数组。

millisecondsTimeout  Int32
等待的毫秒数,或为 Infinite (-1),表示无限期等待。

cancellationToken  CancellationToken
等待任务完成期间要观察的 CancellationToken。

返回
Boolean
如果在分配的时间内所有 true 实例都已完成执行,则为 Task;否则为 false。

属性 UnsupportedOSPlatformAttribute


例外
ObjectDisposedException
tasks 中的一个或多个 Task 对象已释放。

ArgumentNullException
tasks 参数为 null。

AggregateException
至少一个 Task 实例已取消。 如果任务已取消,则 AggregateException 在其 InnerExceptions 集合中包含 OperationCanceledException。

- 或 -

在至少一个 Task 实例的执行过程中引发了异常。

ArgumentOutOfRangeException
millisecondsTimeout 是一个非 -1 的负数,而 -1 表示无限期超时。

ArgumentException
tasks 参数包含一个 null 元素。

OperationCanceledException
已取消 cancellationToken。

注解
参数 cancellationToken 用于取消等待操作。 取消任务是一项不同的操作,由 AggregateException 上面提到的 发出信号。

Task.WaitAll 方法是并行执行所有传入的任务,而不是按顺序一个接一个地执行。Task 是基于 .NET 的异步编程模型,利用多核 CPU 的优势来提高性能,并同时多个任务执行。

Task.WaitAll 在执行时,所有的任务会几乎同时启动,具体的执行顺序取决于线程调度和系统资源。系统会根据可用的线程和 CPU 核心来调度这些任务。这意味着,任务的完成顺序可能与它们在代码中添加到列表的顺序不同。

Task.WaitAll 方法会阻塞调用线程,直到所有任务都完成。

新建一个 .NET Framework 4.8 的 控制台项目,就当前的方法写一个案例:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace task_test1
{
    internal class Program
    {
        static CancellationTokenSource cts = new CancellationTokenSource();
        static void Main(string[] args)
        {
            int timeout = 1000;

            List<Task<(string, bool)>> taskList = new List<Task<(string, bool)>>();
            taskList.Add(PingTest("https://github.com/"));
            taskList.Add(PingTest("https://www.csdn.net/"));
            taskList.Add(PingTest("https://www.zhihu.com/"));
            taskList.Add(PingTest("https://www.microsoft.com/zh-cn/"));
            taskList.Add(PingTest("https://www.baidu.com/"));
            Task<(string, bool)>[] tasks = taskList.ToArray();

            try
            {
                bool allCompleted = Task.WaitAll(tasks, timeout, cts.Token);
                Console.WriteLine("执行结果:{0}", allCompleted);

                foreach (var task in tasks)
                {
                    var tuple = task.Result;
                    Console.WriteLine($"result:{tuple.Item2},url:{tuple.Item1}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("错误:{0}", ex.Message);
            }

            Console.ReadKey();
        }

        static async Task<(string, bool)> PingTest(string ip)
        {
            cts.Token.ThrowIfCancellationRequested();

            PingTool tool = new PingTool();
            bool result = await tool.Ping(ip, cts);
            return (ip, result);
        }
    }
}

internal class PingTool
{
    public async Task<bool> Ping(string url, CancellationTokenSource cts)
    {
        if (string.IsNullOrEmpty(url))
            return false;
        try
        {
            using (HttpClient client = new HttpClient())
            {
                client.Timeout = TimeSpan.FromSeconds(5);
                cts.Token.ThrowIfCancellationRequested();
                var response = await client.GetAsync(url, cts.Token);
                return response.IsSuccessStatusCode;
            }
        }
        catch (Exception)
        {
            return false;
        }
    }
}

运行:

代码中 int timeout = 1000,也就是1秒,在超时的情况下,Task.WaitAll 会返回 false,但是5个 Task 依然全部执行了,所以,timeout 影响的也只有 task 的返回结果了

不超时会返回 true


 

2.WaitAll(Task[])

等待提供的所有 Task 对象完成执行过程。

[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
public static void WaitAll (params System.Threading.Tasks.Task[] tasks);

参数

tasks  Task[]
要等待的 Task 实例的数组。

属性  UnsupportedOSPlatformAttribute


例外
ObjectDisposedException
tasks 中的一个或多个 Task 对象已释放。

ArgumentNullException
tasks 参数为 null。

ArgumentException
tasks 参数包含一个 null 元素。

AggregateException
至少一个 Task 实例已取消。 如果任务取消,则 AggregateException 异常在其 InnerExceptions 集合中包含 OperationCanceledException 异常。

- 或 -

在至少一个 Task 实例的执行过程中引发了异常
 

C# 案例:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;

namespace task_test1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            List<Task<(string, bool)>> taskList = new List<Task<(string, bool)>>();
            taskList.Add(PingTest("https://www.csdn.net/"));
            taskList.Add(PingTest("https://www.zhihu.com/"));
            taskList.Add(PingTest("https://www.microsoft.com/zh-cn/"));
            taskList.Add(PingTest("https://www.baidu.com/"));
            taskList.Add(PingTest("https://github.com/"));
            Task.WaitAll(taskList.ToArray());

            Console.ReadKey();
        }

        static async Task<(string, bool)> PingTest(string ip)
        {
            PingTool tool = new PingTool();
            bool result = await tool.Ping(ip);
            Console.WriteLine("result:{0},时间:{1},url:{2}", result, DateTime.Now, ip);
            return (ip, result);
        }
    }
}

internal class PingTool
{
    public async Task<bool> Ping(string url)
    {
        if (string.IsNullOrEmpty(url))
            return false;
        try
        {
            using (HttpClient client = new HttpClient())
            {
                client.Timeout = TimeSpan.FromSeconds(5);
                var response = await client.GetAsync(url);
                return response.IsSuccessStatusCode;
            }
        }
        catch (System.Exception)
        {
            return false;
        }
    }
}

运行:

3.WaitAll(Task[], Int32)

等待所有提供的 Task 在指定的毫秒数内完成执行。

[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
public static bool WaitAll (System.Threading.Tasks.Task[] tasks, int millisecondsTimeout);

参数
tasks  Task[]
要等待的 Task 实例的数组。

millisecondsTimeout  Int32
等待的毫秒数,或为 Infinite (-1),表示无限期等待。

返回
Boolean
如果在分配的时间内所有 true 实例都已完成执行,则为 Task;否则为 false。

属性   UnsupportedOSPlatformAttribute


例外
ObjectDisposedException
tasks 中的一个或多个 Task 对象已释放。

ArgumentNullException
tasks 参数为 null。

AggregateException
至少一个 Task 实例已取消。 如果任务已取消,则 AggregateException 在其 InnerExceptions 集合中包含 OperationCanceledException。

- 或 -

在至少一个 Task 实例的执行过程中引发了异常。

ArgumentOutOfRangeException
millisecondsTimeout 是一个非 -1 的负数,而 -1 表示无限期超时。

ArgumentException
tasks 参数包含一个 null 元素。

C# 案例:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace task_test1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int timeout = 3000;

            List<Task<(string, bool)>> taskList = new List<Task<(string, bool)>>();
            taskList.Add(PingTest("https://github.com/"));
            taskList.Add(PingTest("https://www.csdn.net/"));
            taskList.Add(PingTest("https://www.zhihu.com/"));
            taskList.Add(PingTest("https://www.microsoft.com/zh-cn/"));
            taskList.Add(PingTest("https://www.baidu.com/"));

            Task<(string, bool)>[] tasks = taskList.ToArray();
            bool allCompleted = Task.WaitAll(tasks, timeout);
            Console.WriteLine("执行结果:{0}", allCompleted);

            foreach (var task in tasks)
            {
                var tuple = task.Result;
                Console.WriteLine($"result:{tuple.Item2},url:{tuple.Item1}");
            }

            Console.ReadKey();
        }

        static async Task<(string, bool)> PingTest(string ip)
        {
            PingTool tool = new PingTool();
            bool result = await tool.Ping(ip);
            return (ip, result);
        }
    }
}

internal class PingTool
{
    public async Task<bool> Ping(string url)
    {
        if (string.IsNullOrEmpty(url))
            return false;
        try
        {
            using (HttpClient client = new HttpClient())
            {
                client.Timeout = TimeSpan.FromSeconds(5);
                var response = await client.GetAsync(url);
                return response.IsSuccessStatusCode;
            }
        }
        catch (System.Exception)
        {
            return false;
        }
    }
}

运行:

4.WaitAll(Task[], CancellationToken)

等待提供的所有 Task 对象完成执行过程(除非取消等待)。

[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
public static void WaitAll (System.Threading.Tasks.Task[] tasks, System.Threading.CancellationToken cancellationToken);

参数
tasks  Task[]
要等待的 Task 实例的数组。

cancellationToken  CancellationToken
等待任务完成期间要观察的 CancellationToken。

属性  UnsupportedOSPlatformAttribute


例外
OperationCanceledException
已取消 cancellationToken。

ArgumentNullException
tasks 参数为 null。

AggregateException
至少一个 Task 实例已取消。 如果任务已取消,则 AggregateException 在其 InnerExceptions 集合中包含 OperationCanceledException。

- 或 -

在至少一个 Task 实例的执行过程中引发了异常。

ArgumentException
tasks 参数包含一个 null 元素。

ObjectDisposedException
tasks 中的一个或多个 Task 对象已释放。

注解
参数 cancellationToken 用于取消等待操作。 取消任务是一项不同的操作,由 如上所述的 发出信号 AggregateException 。

关于取消任务为什么后续依然执行了,请参考第1节的解释

C# 案例:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace task_test1
{
    internal class Program
    {
        static CancellationTokenSource cts = new CancellationTokenSource();
        static void Main(string[] args)
        {
            List<Task<(string, bool)>> taskList = new List<Task<(string, bool)>>();
            taskList.Add(PingTest("https://github.com/"));
            taskList.Add(PingTest("https://www.csdn.net/"));
            taskList.Add(PingTest("https://www.zhihu.com/"));
            taskList.Add(PingTest("https://www.microsoft.com/zh-cn/"));
            taskList.Add(PingTest("https://www.baidu.com/"));
            Task<(string, bool)>[] tasks = taskList.ToArray();

            Task.Run(() =>
            {
                Thread.Sleep(100);
                Console.WriteLine("取消任务");
                cts.Cancel();
            });

            Console.WriteLine("开始执行任务");
            try
            {
                Task.WaitAll(tasks, cts.Token);
            }
            catch (Exception ex)
            {
                Console.WriteLine("错误:{0}", ex.Message);
            }

            Console.ReadKey();
        }

        static async Task<(string, bool)> PingTest(string ip)
        {
            //方法 Task.WaitAll 执行任务会同时执行所有的Task,并等待任务完成
            //而不是一个个按顺序来执行,然后等待结果,所以注释的代码无效
            //if (cts.Token.IsCancellationRequested) 
            //{
            //    Console.WriteLine($"Task for {ip} was cancelled before execution.");
            //    return (ip, false);
            //}
            //cts.Token.ThrowIfCancellationRequested();

            PingTool tool = new PingTool();
            bool result = await tool.Ping(ip, cts);
            Console.WriteLine("result:{0},url:{1}", result, ip);
            return (ip, result);
        }
    }
}

internal class PingTool
{
    public async Task<bool> Ping(string url, CancellationTokenSource cts)
    {
        if (string.IsNullOrEmpty(url))
            return false;
        try
        {
            using (HttpClient client = new HttpClient())
            {
                client.Timeout = TimeSpan.FromSeconds(5);
                cts.Token.ThrowIfCancellationRequested();
                var response = await client.GetAsync(url, cts.Token);
                return response.IsSuccessStatusCode;
            }
        }
        catch (Exception)
        {
            return false;
        }
    }
}

运行:

5.WaitAll(Task[], TimeSpan)

等待所有提供的可取消 Task 对象在指定的时间间隔内完成执行。

[System.Runtime.Versioning.UnsupportedOSPlatform("browser")]
public static bool WaitAll (System.Threading.Tasks.Task[] tasks, TimeSpan timeout);

参数
tasks  Task[]
要等待的 Task 实例的数组。

timeout  TimeSpan
表示等待毫秒数的 TimeSpan,或表示 -1 毫秒(无限期等待)的 TimeSpan。

返回
Boolean
如果在分配的时间内所有 true 实例都已完成执行,则为 Task;否则为 false。

属性  UnsupportedOSPlatformAttribute


例外
ObjectDisposedException
tasks 中的一个或多个 Task 对象已释放。

ArgumentNullException
tasks 参数为 null。

AggregateException
至少一个 Task 实例已取消。 如果任务已取消,则 AggregateException 在其 InnerExceptions 集合中包含 OperationCanceledException。

- 或 -

在至少一个 Task 实例的执行过程中引发了异常。

ArgumentOutOfRangeException
timeout 为 -1 毫秒以外的负数,表示无限期超时。

- 或 -

timeout 大于 Int32.MaxValue。

ArgumentException
tasks 参数包含一个 null 元素。
 

C# 案例:

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

namespace task_test1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            List<Task<(string, bool)>> taskList = new List<Task<(string, bool)>>();
            taskList.Add(PingTest("https://github.com/"));
            taskList.Add(PingTest("https://www.csdn.net/"));
            taskList.Add(PingTest("https://www.zhihu.com/"));
            taskList.Add(PingTest("https://www.microsoft.com/zh-cn/"));
            taskList.Add(PingTest("https://www.baidu.com/"));

            Task<(string, bool)>[] tasks = taskList.ToArray();
            bool allCompleted = Task.WaitAll(tasks, TimeSpan.FromSeconds(1));
            Console.WriteLine("执行结果:{0}", allCompleted);

            foreach (var task in tasks)
            {
                var tuple = task.Result;
                Console.WriteLine($"result:{tuple.Item2},url:{tuple.Item1}");
            }

            Console.ReadKey();
        }

        static async Task<(string, bool)> PingTest(string ip)
        {
            PingTool tool = new PingTool();
            bool result = await tool.Ping(ip);
            return (ip, result);
        }
    }
}

internal class PingTool
{
    public async Task<bool> Ping(string url)
    {
        if (string.IsNullOrEmpty(url))
            return false;
        try
        {
            using (HttpClient client = new HttpClient())
            {
                client.Timeout = TimeSpan.FromSeconds(5);
                var response = await client.GetAsync(url);
                return response.IsSuccessStatusCode;
            }
        }
        catch (System.Exception)
        {
            return false;
        }
    }
}

运行:

结束

如果这个帖子对你有用,欢迎 关注 + 点赞 + 留言,谢谢

end

  • 11
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熊思宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值