C# 在c中以异步方式启动多个“任务”

C# 在c中以异步方式启动多个“任务”,c#,.net,multithreading,task,parallels,C#,.net,Multithreading,Task,Parallels,我有两个简单的异步方法 static async Task First() { for (int i = 0; i < 2; i++) { await Task.Delay(200); Console.WriteLine($"First method: {i}"); } } static async Task Second() { for (int i = 0; i < 2; i++) {

我有两个简单的异步方法

static async Task First()
{
    for (int i = 0; i < 2; i++)
    {
        await Task.Delay(200);
        Console.WriteLine($"First method: {i}");
    }
}

static async Task Second()
{
    for (int i = 0; i < 2; i++)
    {
        await Task.Delay(200);
        Console.WriteLine($"Second method: {i}");
    }
}
其次,创建一个任务数组并通过迭代调用它们。但结果是相似的

   var tasks = new Task[] { First(), Second() };
   foreach (var t in tasks)
   {
       await Task.Run(async () => await t);
   }

   //Second method: 0
   //First method: 0
   //Second method: 1
   //First method: 1
我称之为并行的第三个示例,其结果是预期的

在最后一个例子中,我立即开始任务。结果也和预期的一样

     var tasks = new Task[] { First(), Second() };
     await Task.WhenAll(tasks);

     //First method: 0
     //Second method: 0
     //Second method: 1
     //First method: 1

所以我的问题是:这4种调用异步任务的方法之间有什么区别?哪种方法是最好的使用方法?

您得到的结果可以用以下方法解释

您的方法按顺序运行,信不信由你,wait实际上意味着wait,因为不涉及其他任务,并且您的方法不会在未被观察的情况下运行 任务一添加到阵列中就开始了,然后将工作卸载到另一个任务中并等待,但是您将工作负载作为异步void运行,而异步void又在未被观察的情况下运行,因此每个外部任务都会立即返回。结果的顺序取决于任务调度程序和两个线程之间的竞争。 您正在使用TPL方法来潜在地启动任务,以启动以异步方式运行工作负载且未被观察到的任务,例如Parallel.Foreach立即返回。结果的顺序取决于任务调度程序和两个线程之间的竞争。 您正在开始两项任务,并等待这两项任务的完成。结果的顺序取决于任务调度程序和两个线程之间的竞争。 哪一种是最好的使用方法

这完全取决于你想要实现什么。。。由于他们出于不同的原因所做的事情略有不同,而且有些事情完全是多余的,所以没有正确的答案

但是,对于示例方法,如果您希望等待2个异步工作负载异步完成,则Task.WhenAll似乎是最简洁、最明智的方法

var tasks = new Task[] { First(), Second() };
await Task.WhenAll(tasks);

你得到的结果可以用以下几点来解释

您的方法按顺序运行,信不信由你,wait实际上意味着wait,因为不涉及其他任务,并且您的方法不会在未被观察的情况下运行 任务一添加到阵列中就开始了,然后将工作卸载到另一个任务中并等待,但是您将工作负载作为异步void运行,而异步void又在未被观察的情况下运行,因此每个外部任务都会立即返回。结果的顺序取决于任务调度程序和两个线程之间的竞争。 您正在使用TPL方法来潜在地启动任务,以启动以异步方式运行工作负载且未被观察到的任务,例如Parallel.Foreach立即返回。结果的顺序取决于任务调度程序和两个线程之间的竞争。 您正在开始两项任务,并等待这两项任务的完成。结果的顺序取决于任务调度程序和两个线程之间的竞争。 哪一种是最好的使用方法

这完全取决于你想要实现什么。。。由于他们出于不同的原因所做的事情略有不同,而且有些事情完全是多余的,所以没有正确的答案

但是,对于示例方法,如果您希望等待2个异步工作负载异步完成,则Task.WhenAll似乎是最简洁、最明智的方法

var tasks = new Task[] { First(), Second() };
await Task.WhenAll(tasks);

哪一种是最好的使用方法?你对最佳的定义是什么?1和4至少不会创建不必要的线程,也不会混合彼此不太喜欢的概念。现在这取决于你需要什么。1将按顺序执行,第二个将在第一个完成后执行,第四个将异步执行,这与并行执行不同,并等待两者完成。我说的最佳性能是指性能。第二个和第三个例子呢?为什么第二个示例不像第一个示例那样工作?为什么第二次迭代不等待第一次迭代和等待的任务?好的,2:异步启动两个任务。这意味着它们可能在两个线程上并行执行,也可能不并行执行。然后创建并等待另外两个任务,它们依次等待执行。因此,这里执行与等待它们的顺序是分开的。在第一个代码段中,首先执行并立即等待它。这意味着它可能在单独的线程上执行,也可能不在单独的线程上执行,但无论如何,第二个线程只会在第一个线程完成后启动。所以这里的执行顺序就是等待它们的顺序。为了评估哪一个性能更好,我强烈建议做一个基准测试,见benchmark.NET。记住,只有当第二个不依赖于第一个的结果时,4才有意义。1或4的执行方式可能取决于第一个和第二个的实现、加载、在计算机上应用程序旁边执行的内容。。。所以这可能很难预测。1,4-好。2,3-糟糕。参考:和。哪种方法是最好的使用方法?你对最佳的定义是什么?1和4至少不要创建不必要的线程和混合不必要的概念
特别喜欢彼此。现在这取决于你需要什么。1将按顺序执行,第二个将在第一个完成后执行,第四个将异步执行,这与并行执行不同,并等待两者完成。我说的最佳性能是指性能。第二个和第三个例子呢?为什么第二个示例不像第一个示例那样工作?为什么第二次迭代不等待第一次迭代和等待的任务?好的,2:异步启动两个任务。这意味着它们可能在两个线程上并行执行,也可能不并行执行。然后创建并等待另外两个任务,它们依次等待执行。因此,这里执行与等待它们的顺序是分开的。在第一个代码段中,首先执行并立即等待它。这意味着它可能在单独的线程上执行,也可能不在单独的线程上执行,但无论如何,第二个线程只会在第一个线程完成后启动。所以这里的执行顺序就是等待它们的顺序。为了评估哪一个性能更好,我强烈建议做一个基准测试,见benchmark.NET。记住,只有当第二个不依赖于第一个的结果时,4才有意义。1或4的执行方式可能取决于第一个和第二个的实现、加载、在计算机上应用程序旁边执行的内容。。。所以这可能很难预测。1,4-好。2,3-糟糕。请参阅:和。关于2的解释,不涉及异步void。Task.Run理解异步委托。关于2的解释,不涉及异步void。Task.Run理解异步委托。
var tasks = new Task[] { First(), Second() };
await Task.WhenAll(tasks);