Подтвердить что ты не робот

Использовать Task.WaitAll() для обработки ожидаемых задач?

В идеале, что я хочу сделать, это задержать задачу с неблокирующим режимом, а затем дождаться завершения всех задач. Я попытался добавить объект задачи, возвращенный Task.Delay, а затем использовать Task.WaitAll, но похоже, что это не поможет. Как мне решить эту проблему?

class Program
{
    public static async void Foo(int num)
    {
        Console.WriteLine("Thread {0} - Start {1}", Thread.CurrentThread.ManagedThreadId, num);

        var newTask = Task.Delay(1000);
        TaskList.Add(newTask);
        await newTask;

        Console.WriteLine("Thread {0} - End {1}", Thread.CurrentThread.ManagedThreadId, num);
    }

    public static List<Task> TaskList = new List<Task>();

    public static void Main(string[] args)
    {
        for (int i = 0; i < 3; i++)
        {
            int idx = i;
            TaskList.Add(Task.Factory.StartNew(() => Foo(idx)));
        }

        Task.WaitAll(TaskList.ToArray());
    }
}
4b9b3361

Ответ 1

Это то, чего вы пытаетесь достичь?

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

namespace ConsoleApplication
{
    class Program
    {
        public static async Task Foo(int num)
        {
            Console.WriteLine("Thread {0} - Start {1}", Thread.CurrentThread.ManagedThreadId, num);

            await Task.Delay(1000);

            Console.WriteLine("Thread {0} - End {1}", Thread.CurrentThread.ManagedThreadId, num);
        }

        public static List<Task> TaskList = new List<Task>();

        public static void Main(string[] args)
        {
            for (int i = 0; i < 3; i++)
            {
                int idx = i;
                TaskList.Add(Foo(idx));
            }

            Task.WaitAll(TaskList.ToArray());
            Console.WriteLine("Press Enter to exit...");
            Console.ReadLine();
        }
    }
}

Вывод:

Thread 10 - Start 0
Thread 10 - Start 1
Thread 10 - Start 2
Thread 6 - End 0
Thread 6 - End 2
Thread 6 - End 1
Press Enter to exit...

Ответ 2

То, что нужно знать, состоит в том, что, поскольку Foo является асинхронным, он сам является Задачей. В вашем примере есть задачи, которые просто запускают задачу Foo, но не ждут ее.

Другими словами, Task.WaitAll(TaskList.ToArray()) просто ждет запуска каждого Task.Delay, но он не ждет завершения всех этих задач.

Это может быть то, чего вы пытаетесь достичь:

class Program
{
    public static async Task Foo(int num)
    {
        Console.WriteLine("Thread {0} - Start {1}", Thread.CurrentThread.ManagedThreadId, num);

        var newTask = Task.Delay(1000);

        await newTask;
        Console.WriteLine("Thread {0} - End {1}", Thread.CurrentThread.ManagedThreadId, num);

    }

    public static List<Task> TaskList = new List<Task>();

    public static void Main(string[] args)
    {
        for (int i = 0; i < 3; i++)
        {
            int idx = i;

            Task fooWrappedInTask = Task.Run(() => Foo(idx));
            TaskList.Add(fooWrappedInTask);
        }

        Task.WaitAll(TaskList.ToArray());
        Console.WriteLine("Finished waiting for all of the tasks: - Thread {0}", Thread.CurrentThread.ManagedThreadId);
    }
}

Я тестировал это, и он производит вывод на консоль, на который вы нацеливаетесь.


Основное отличие здесь в том, что мы вызываем Task.Run вместо Task.Factory.StartNew.

У вас может быть Task, который возвращает Task, который может даже вернуть еще один Task. Вы могли бы подумать об этом как о "цепочке" задач.

Task.Run возвращает a Task, которые представляют конечную задачу в цепочке. Когда вы ждете его, вы ожидаете завершения каждой ссылки в цепочке задач.

Для сравнения, Task.Factory.StartNew возвращает задачу, которая представляет первое звено в цепочке. После того, как вы дождались этого, вы остаетесь с остальной цепью, чтобы дождаться. Это прекрасно в подавляющем большинстве случаев, когда Task возвращает то, что не является другим Task.