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

der*_*khh 27 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());
    }
}
Run Code Online (Sandbox Code Playgroud)

nos*_*tio 43

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

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

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

  • 谢谢!我刚刚注意到你还将Foo的返回类型从void更改为Task.是的,改回来就会看到与你写的相同的行为.:) (3认同)

And*_*erd 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经测试了这个,它产生了你想要的控制台输出.


这里的主要区别是我们打电话Task.Run而不是Task.Factory.StartNew.

你可能有一个Task返回a Task,甚至可能返回另一个Task.您会将此视为任务的"链条".

Task.Run返回Task表示链中的最终任务的.当您等待它时,您正在等待完成任务链中的每个链接.

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

  • 你在这里创建嵌套任务,`Task.Run`自动解包,这是不必要的,IMO.否则,代码似乎与[我提出的版本](http://stackoverflow.com/a/19849906/1768303)没有什么不同.不确定这是OP想要的. (2认同)