具有异步lambda和Task.WaitAll的Task.Factory.StartNew

Jac*_*rts 16 .net c# lambda task-parallel-library async-await

我正在尝试使用Task.WaitAll任务列表.事情是任务是异步lambda,Tasks.WaitAll因为它永远不会等待.

这是一个示例代码块:

List<Task> tasks = new List<Task>();
tasks.Add(Task.Factory.StartNew(async () =>
{
    using (dbContext = new DatabaseContext())
    {
        var records = await dbContext.Where(r => r.Id = 100).ToListAsync();
        //do long cpu process here...
    }
}
Task.WaitAll(tasks);
//do more stuff here  
Run Code Online (Sandbox Code Playgroud)

这不会因为异步lambda而等待.那我该如何等待我的lambda中的I/O操作呢?

Cha*_*ger 19

Task.Factory.StartNew不识别async委托,因为没有重载接受返回a的函数Task.

这加上其他原因(参见StartNew是危险的)是你应该在Task.Run这里使用的原因:

tasks.Add(Task.Run(async () => ...
Run Code Online (Sandbox Code Playgroud)

  • 太糟糕了,Task.run没有给你`TaskCreationOptions` (2认同)

Yuv*_*kov 19

这不会因为异步lambda而等待.那我该如何等待我的lambda中的I/O操作呢?

之所以Task.WaitAll不等待async lambda提供的IO工作的完成是因为Task.Factory.StartNew实际返回了一个Task<Task>.由于您的列表是List<Task>(并且Task<T>派生自Task),因此您等待启动的外部任务StartNew,同时忽略由异步lambda创建的内部任务.这就是为什么他们说对于异步Task.Factory.StartNew危险的.

你怎么能解决这个问题?您可以显式调用Task<Task>.Unwrap()以获取内部任务:

List<Task> tasks = new List<Task>();
tasks.Add(Task.Factory.StartNew(async () =>
{
    using (dbContext = new DatabaseContext())
    {
        var records = await dbContext.Where(r => r.Id = 100).ToListAsync();
        //do long cpu process here...
    }
}).Unwrap());
Run Code Online (Sandbox Code Playgroud)

或者像其他人说的那样,你可以打电话Task.Run:

tasks.Add(Task.Run(async () => /* lambda */);
Run Code Online (Sandbox Code Playgroud)

此外,既然你想做正确的事情,你会想要使用Task.WhenAll,为什么是异步等待,而不是Task.WaitAll同步阻止:

await Task.WhenAll(tasks);
Run Code Online (Sandbox Code Playgroud)