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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19849847/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 15:59:42  来源:igfitidea点击:

Use Task.WaitAll() to handle awaited tasks?

c#multithreadingasync-await

提问by derekhh

Ideally what I want to do is to delay a task with a non-blocking mode and then wait for all the tasks to complete. I've tried to add the task object returned by Task.Delay and then use Task.WaitAll but seems this won't help. How should I solve this problem?

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

采纳答案by noseratio

Is this what you are trying to achieve?

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

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

Output:

输出:

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

回答by Andrew Shepherd

The thing to be aware of is that because Foo is async, it itself is a Task. Your example has tasks which simply kick off the Footask, but don't wait for it.

需要注意的是,因为 Foo 是异步的,所以它本身就是一个任务。您的示例具有简单地启动Foo任务的任务,但不要等待它。

In other words, Task.WaitAll(TaskList.ToArray())is simply waiting for each Task.Delayto start, but it is not waiting for all of these tasks to finish.

换句话说,Task.WaitAll(TaskList.ToArray())只是等待每个任务Task.Delay开始,而不是等待所有这些任务完成。

This might be what you are trying to achieve:

这可能是您想要实现的目标:

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

I've tested this, and it produces the console output you are aiming for.

我已经对此进行了测试,它会生成您想要的控制台输出。



这里的主要区别是我们调用Task.RunTask.Run而不是Task.Factory.StartNewTask.Factory.StartNew.

You might have a Taskthat returns a Task, which might even return another Task. You would think of this as a 'chain' of tasks.

您可能有Task返回 a 的 a Task,甚至可能返回 another Task。你会认为这是一个“链”的任务。

Task.Runreturns a Taskthat represent the final task in the chain. When you wait for it, you are waiting for the every link in the chain of tasks to complete.

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

In comparison, Task.Factory.StartNewreturns a task that represents the first link in the chain. After you have waited for it, you are left with the rest of the chain to wait for. This is fine in the cases where the Taskreturns something that isn't another Task.

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