具有异步lambda和Task.WaitAll的Task.Factory.StartNew
我正在尝试在任务列表中使用Task.WaitAll
。 事情是任务是一个异步lambda,它打破Tasks.WaitAll
因为它永远不会等待。
这是一个示例代码块:
List tasks = new List(); 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
。 由于列表是List
(并且Task
派生自Task
),因此等待StartNew
启动的外部任务,同时忽略 async lambda创建的内部任务。 这就是为什么他们说Task.Factory.StartNew
对于异步是危险的 。
你怎么能解决这个问题? 您可以显式调用Task
以获取内部任务:
List tasks = new List (); 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 tasks = new List (); 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 tasks = new List (); 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... }); } } }