await Task.WhenAll不等待所有任务完成

时间:2015-05-28 10:50:25

标签: c# .net asynchronous async-await task-parallel-library

我最近一直在尝试使用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());

在这种情况下,我一开始并不确定它是否相等。

有一些类似的问题,但我的例子非常简单,我在现有的答案中找不到解释。

3 个答案:

答案 0 :(得分:11)

您遇到元素数量不一致的原因是List<T> 线程安全

await Task.Delay(100)之后,向列表添加元素的continuation发生在任意线程池并发上,因为正在执行多个任务。如果您将实现切换为使用ConcurrentBag<int>,则不会发生这种情况。

答案 1 :(得分:2)

在将int添加到列表之前尝试添加锁(列表)。您可能会从多个线程添加到非线程安全列表。

答案 2 :(得分:2)

  • 不要使用带有多线程代码的列表 - 不安全的访问 - 使用System.Collections.Concurrent中的一个集合。
  • 永远不要使用&#39; async void&#39; - 在.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);
        }
    }
}