Task.Factory.StartNew with async lambda and Task.WaitAll
本文关键字:Task and WaitAll lambda with Factory StartNew async | 更新日期: 2023-09-27 17:56:05
我正在尝试在任务列表中使用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
这不会因为异步 lambda 而等待。 那么,我应该如何等待 lambda 中的 I/O 操作呢?
>Task.Factory.StartNew
无法识别async
委托,因为没有重载接受返回Task
的函数。
再加上其他原因(请参阅StartNew是危险的)是您应该在此处使用Task.Run
的原因:
tasks.Add(Task.Run(async () => ...
这不会因为异步 lambda 而等待。那我应该怎么做 等待我的 lambda 中的 I/O 操作?
Task.WaitAll
不等待异步 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());
或者像其他人说的那样,你可以打电话给Task.Run
:
tasks.Add(Task.Run(async () => /* lambda */);
另外,由于你想把事情做好,你会想要使用 Task.WhenAll
,为什么异步等待,而不是同步阻塞的Task.WaitAll
:
await Task.WhenAll(tasks);
你可以
这样做。
void Something()
{
List<Task> tasks = new List<Task>();
tasks.Add(ReadAsync());
Task.WaitAll(tasks.ToArray());
}
async Task ReadAsync() {
using (dbContext = new DatabaseContext())
{
var records = await dbContext.Where(r => r.Id = 100).ToListAsync();
//do long cpu process here...
}
}
你必须使用Task.ContinueWith
方法。喜欢这个
List<Task> tasks = new List<Task>();
tasks.Add(Task.Factory.StartNew(() =>
{
using (dbContext = new DatabaseContext())
{
return dbContext.Where(r => r.Id = 100).ToListAsync().ContinueWith(t =>
{
var records = t.Result;
// do long cpu process here...
});
}
}
}