32

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

2 回答 2

48

这是你想要达到的目标吗?

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

输出:

线程 10 - 开始 0
线程 10 - 开始 1
线程 10 - 开始 2
线程 6 - 结束 0
线程 6 - 结束 2
线程 6 - 结束 1
按 Enter 退出...
于 2013-11-08T01:17:00.447 回答
30

需要注意的是,因为 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返回 a 的 a Task,它甚至可能返回另一个Task。你会认为这是一个任务“链”。

Task.Run返回Task代表链中最终任务的 a。当您等待它时,您正在等待任务链中的每个环节完成。

相比之下,Task.Factory.StartNew返回代表链中第一个链接的任务。在您等待它之后,剩下的就是链条的其余部分等待。Task在返回的东西不是 another的情况下,这很好Task

于 2013-11-08T01:44:35.170 回答