C# Task.Factory.StartNew中的异步方法在继续之前等待所有任务

C# Task.Factory.StartNew中的异步方法在继续之前等待所有任务,c#,async-await,task,multitasking,C#,Async Await,Task,Multitasking,我有以下代码: public async Task<bool> ExecuteAsync() { return await someresult; } public async Task DoSomethingAsync() { var tasks = new List<Task>(); foreach (var item in someList) { var task = Task.Factory.S

我有以下代码:

public async Task<bool> ExecuteAsync()
{        
    return await someresult;
}


public async Task DoSomethingAsync()
{

   var tasks = new List<Task>();

   foreach (var item in someList)
   {

         var task = Task.Factory.StartNew(async () =>
                    {
                          await ExecuteAsync();
                    });

         tasks.Add(task);
   }


   await Task.WhenAll(tasks);

   // The program execution should stop here and next code should be run when all tasks are completed


}
公共异步任务ExecuteAsync()
{        
返回等待结果;
}
公共异步任务DoSomethingAsync()
{
var tasks=新列表();
foreach(someList中的变量项)
{
var task=task.Factory.StartNew(异步()=>
{
等待ExecuteAsync();
});
任务。添加(任务);
}
等待任务。何时(任务);
//程序执行应在此停止,下一个代码应在所有任务完成后运行
}
基本上,我处于一个foreach循环中,在这个循环中,我为每个项目启动一个新任务


一旦所有任务启动,我希望代码在
wait Task.WhenAll(任务)之后。当然,所有这些都是异步的,因此我想知道这是否可能?因为所有任务都是异步的,所以执行不会在所有(任务)时停止,而是继续,即使如此,也不是所有任务都已完成。如何解决此问题?

首先,为什么要为循环中的每个任务浪费线程池,您的代码可以编写为:

public  Task<bool> ExecuteAsync()
{
    return  ItReturnsATask();
}

public async Task DoSomethingAsync()
{

    var tasks = new List<Task>();

      foreach (var item in someList)
      {
        //ExecuteAsync can be replace by ItReturnsATask if there's no extra processing
            tasks.Add(ExecuteAsync());
      }

     await Task.WhenAll(tasks);
}
public Task ExecuteAsync()
{
返回ItReturnsATask();
}
公共异步任务DoSomethingAsync()
{
var tasks=新列表();
foreach(someList中的变量项)
{
//如果没有额外的处理,ExecuteAsync可以被iTreturnsTask替换
tasks.Add(ExecuteAsync());
}
等待任务。何时(任务);
}

您的代码忽略了异步的要点,它从线程池创建了几个线程,并使用它们,这些线程在这里被浪费了。至于您的实际问题,
之后的任何内容都会等待任务。当所有(任务)
在所有任务完成之前都不会执行(假设我们捕获的是当前上下文)。

您为什么要使用
Task.Factory.StartNew
?你被困在.NET4.0上了吗?如果没有,请使用
Task.Run
而不是,
async()=>wait ExecuteAsync()
没有任何意义,您必须使用
Task.Run(()=>ExecuteAsync)
StartNew不直接支持异步lambadas。
task
的类型将是
task
,而
whalll
将不会像您期望的那样运行。使用Task.Run,或者在将其添加到列表之前需要调用
.Unwrap()
。@CamiloTerevinto:我的理解是,您不应该在循环中运行Task.Run。我错了吗?@user2818430
Task.Run
优于
Task.Factory.StartNew
对于正常情况,您正在做一个危险的假设,即此代码运行在一个无上下文框架上,这可能是真的,也可能不是真的。在WinForms、WPF、Xamarin和WebForms中,使用线程池线程和不使用线程之间存在巨大差异。@CamiloTerevinto如果
ExecuteAsync
是一种不需要捕获当前同步上下文的方法,则应编写为不使用它,而不是简单地期望使用它的每个调用者从上下文无关的线程调用它。在不需要(也不应该使用)当前同步上下文的情况下使用该方法将是该方法中的一个错误。@Camiloterevento I假设基于这两篇文章,你能给我一篇关于这些巨大差异的文章吗?@Servy是的,应该是。但事实上,我们不知道ExecuteAsync执行了什么,也不知道调用前后发生了什么。因此,虽然一般的建议是正确的,但我认为您不能如此轻松地进行调用(例如,想象
ExecuteAsync
来自第三方)@CamiloTerevinto如果方法编写不正确,并且实际上使用了当前的同步上下文,那么应该纠正该方法,而不是使用
StartNew
Run
在此处调用它。与其试图破解一个bug,不如修复这个bug,如果它存在的话(你只是假设它存在)。