简体   繁体   中英

await Task.WhenAll does not wait for all tasks to complete

I've been experimenting lately with async-await and I still cannot get some things to work.

Why does this code not always result with '100' being written to console?

Should not

await Task.WhenAll(tasks); 

wait for all 100 tasks to complete?

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);
}

Am I doing something wrong or is this some kind of async-await downside?

Same goes with

Task.WaitAll(tasks.ToArray());

which I wasn't sure at first if it's equal in this case.

There are a few similar questions but my example is really simple and I can't find explanation in the existing answers.

The reason you experience the inconsistency in the number of elements is because List<T> isn't thread-safe .

After you await Task.Delay(100) , the continuation, which adds elements to the list happens on an arbitrary thread pool, concurrently , because multiple tasks are executing. If you switch you implementation to use ConcurrentBag<int> , this wont happen.

Try adding a lock(list) before adding the int to the list. You potentially adding from multiple threads to a non thread safe list.

  • Do not use list with multi-threaded code - access in unsafe - use one of the collections in System.Collections.Concurrent.
  • Never use 'async void' - it is a horrible thing to support async click handlers in .Net UI applications ( http://haacked.com/archive/2014/11/11/async-void-methods/ )

The following code will work for your purposes:

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);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM