C# Task 使用 WhenAll 和 WaitAll 需要注意的坑
1.无限等待
我们在使用 WhenAll 和 WaitAll 时,一定得要注意:1.必须添加超时时间,防止无限等待 2.等待的 Task 一定要保证是启动的。
比如下面这种写法:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TaskForWhenAll
{
class Program
{
static void Main(string[] args)
{
var taskList = new List<Task>();
for (int i = 0; i < 5; i++)
{
taskList.Add(new Task(() =>
{
Console.WriteLine("Task {0} is finished", Task.CurrentId);
}));
}
// await Task.WhenAny(taskList);
Task.WaitAll(taskList.ToArray());
Console.WriteLine("exit");
}
}
}
将不会正常运行,会一直无限等待,因为 new Task 这样创建出来的 Task 不会自动运行,需要手动调用 Task.Start
改造一下代码:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TaskForWhenAll
{
class Program
{
static void Main(string[] args)
{
var taskList = new List<Task>();
for (int i = 0; i < 5; i++)
{
taskList.Add(Task.Run(() =>
{
Console.WriteLine("Task {0} is finished", Task.CurrentId);
}));
}
// await Task.WhenAny(taskList);
Task.WaitAll(taskList.ToArray());
Console.WriteLine("exit");
}
}
}
使用 Task.Run 创建的 Task 是会自动运行的
2.没有期望的等待
我们在创建 Task 时,可能会定义一个异步委托,以便方便在 Task 里面使用 await,例如:
class Program
{
static async Task Main(string[] args)
{
var taskList = new List<Task>();
for (int i = 0; i < 5; i++)
{
taskList.Add(Task.Factory.StartNew(async () =>
{
await Task.Delay(3000);
Console.WriteLine("Task {0} is finished", Task.CurrentId);
}));
}
await Task.WhenAny(taskList);
Console.WriteLine("exit");
}
}
直接运行会发生什么
直接就退出了,并没有等待所有任务执行完毕。
我们换成 Task.Run 是可以正常运行的,这是为什么呢?这是因为我们这种写法,会把 Task Result 包装一层,我们需要得到期望的结果需要解除包装 UnWrap,Task.Factory.StartNew和Task.Run区别之一就有Task.Run会自动执行Unwrap操作。
扩展阅读:https://www.cnblogs.com/Leo_wl/archive/2012/09/21/2696342.html
我们改造一下代码
taskList.Add(Task.Factory.StartNew(async () =>
{
await Task.Delay(3000);
Console.WriteLine("Task {0} is finished", Task.CurrentId);
}).Unwrap());
就能按照我们期望的去运行
目前学习.NET Core 最好的教程 .NET Core 官方教程 ASP.NET Core 官方教程