await Task.WhenAll 不等待所有任务完成
await Task.WhenAll does not wait for all tasks to complete
我最近一直在尝试使用 async-await,但我仍然无法让一些东西正常工作。
为什么此代码并不总是将“100”写入控制台?
不应该
await Task.WhenAll(tasks);
是否等待所有 100 个任务完成?
static List<int> list = new List<int>();
static void Main(string[] args)
{
NewMethod();
Console.ReadLine();
}
private async static void NewMethod()
{
var tasks = new List<Task>();
for (int i = 0; i < 100; i++)
{
tasks.Add(Func(i));
}
Console.WriteLine("Lol");
await Task.WhenAll(tasks);
Console.WriteLine(list.Count());
}
static async Task Func(int i)
{
await Task.Delay(100);
list.Add(i);
}
我是不是做错了什么或者这是某种异步等待的缺点?
同样适用于
Task.WaitAll(tasks.ToArray());
起初我不确定在这种情况下它是否相等。
有几个类似的问题,但我的例子真的很简单,我在现有的答案中找不到解释。
尝试在将 int 添加到列表之前添加一个锁(列表)。您可能从多个线程添加到非线程安全列表。
您遇到元素数量不一致的原因是因为 List<T>
不是 线程安全的 。
在 await Task.Delay(100)
之后,将元素添加到列表的延续发生在任意线程池上,并发,因为多个任务正在执行。如果您将实现切换为使用 ConcurrentBag<int>
,则不会发生这种情况。
- 不要在多线程代码中使用列表 - 访问不安全 - 使用 System.Collections.Concurrent 中的集合之一。
- 切勿使用 'async void' - 在 .Net UI 应用程序中支持异步点击处理程序是一件可怕的事情 (http://haacked.com/archive/2014/11/11/async-void-methods/)
以下代码可满足您的需要:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ConsoleApplication8
{
class Program
{
static readonly BlockingCollection<int> List = new BlockingCollection<int>();
static void Main(string[] args)
{
var application = NewMethod();
application.Wait();
Console.ReadLine();
}
private async static Task NewMethod()
{
var tasks = new List<Task>();
for (int i = 0; i < 100; i++)
{
tasks.Add(Func(i));
}
Console.WriteLine("Lol");
await Task.WhenAll(tasks);
Console.WriteLine(List.Sum());
}
static async Task Func(int i)
{
await Task.Delay(100);
List.Add(i);
}
}
}
我最近一直在尝试使用 async-await,但我仍然无法让一些东西正常工作。
为什么此代码并不总是将“100”写入控制台?
不应该
await Task.WhenAll(tasks);
是否等待所有 100 个任务完成?
static List<int> list = new List<int>();
static void Main(string[] args)
{
NewMethod();
Console.ReadLine();
}
private async static void NewMethod()
{
var tasks = new List<Task>();
for (int i = 0; i < 100; i++)
{
tasks.Add(Func(i));
}
Console.WriteLine("Lol");
await Task.WhenAll(tasks);
Console.WriteLine(list.Count());
}
static async Task Func(int i)
{
await Task.Delay(100);
list.Add(i);
}
我是不是做错了什么或者这是某种异步等待的缺点?
同样适用于
Task.WaitAll(tasks.ToArray());
起初我不确定在这种情况下它是否相等。
有几个类似的问题,但我的例子真的很简单,我在现有的答案中找不到解释。
尝试在将 int 添加到列表之前添加一个锁(列表)。您可能从多个线程添加到非线程安全列表。
您遇到元素数量不一致的原因是因为 List<T>
不是 线程安全的 。
在 await Task.Delay(100)
之后,将元素添加到列表的延续发生在任意线程池上,并发,因为多个任务正在执行。如果您将实现切换为使用 ConcurrentBag<int>
,则不会发生这种情况。
- 不要在多线程代码中使用列表 - 访问不安全 - 使用 System.Collections.Concurrent 中的集合之一。
- 切勿使用 'async void' - 在 .Net UI 应用程序中支持异步点击处理程序是一件可怕的事情 (http://haacked.com/archive/2014/11/11/async-void-methods/)
以下代码可满足您的需要:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ConsoleApplication8
{
class Program
{
static readonly BlockingCollection<int> List = new BlockingCollection<int>();
static void Main(string[] args)
{
var application = NewMethod();
application.Wait();
Console.ReadLine();
}
private async static Task NewMethod()
{
var tasks = new List<Task>();
for (int i = 0; i < 100; i++)
{
tasks.Add(Func(i));
}
Console.WriteLine("Lol");
await Task.WhenAll(tasks);
Console.WriteLine(List.Sum());
}
static async Task Func(int i)
{
await Task.Delay(100);
List.Add(i);
}
}
}