使用Task.WaitAll()来处理等待的任务?

时间:2013-11-08 01:09:51

标签: c# multithreading async-await

理想情况下,我想要做的是使用非阻塞模式延迟任务,然后等待所有任务完成。我试图添加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());
    }
}

2 个答案:

答案 0 :(得分:42)

这是你想要实现的目标吗?

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...

答案 1 :(得分:20)

需要注意的是,因为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返回代表链中最终任务的Task。当您等待它时,您正在等待完成任务链中的每个链接。

相比之下,Task.Factory.StartNew返回表示链中第一个链接的任务。在等待之后,您将与链的其余部分一起等待。在Task返回的内容不是另一个Task的绝大多数情况下,这样做很好。