Task.Factory.StartNew 使用异步 lambda 和 Task.WaitAll
Task.Factory.StartNew with async lambda and Task.WaitAll
我正尝试在任务列表中使用 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.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...
});
}
}
}
Task.Factory.StartNew
无法识别 async
委托,因为没有接受返回 Task
的函数的重载。
这加上其他原因(参见 StartNew is dangerous)是您应该在此处使用 Task.Run
的原因:
tasks.Add(Task.Run(async () => ...
你可以这样做。
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...
}
}
This doesn't wait because of the async lambda. So how am I supposed to
await I/O operations in my lambda?
Task.WaitAll
不等待异步 lambda 提供的 IO 工作完成的原因是因为 Task.Factory.StartNew
实际上 returns 一个 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);
我正尝试在任务列表中使用 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.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...
});
}
}
}
Task.Factory.StartNew
无法识别 async
委托,因为没有接受返回 Task
的函数的重载。
这加上其他原因(参见 StartNew is dangerous)是您应该在此处使用 Task.Run
的原因:
tasks.Add(Task.Run(async () => ...
你可以这样做。
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...
}
}
This doesn't wait because of the async lambda. So how am I supposed to await I/O operations in my lambda?
Task.WaitAll
不等待异步 lambda 提供的 IO 工作完成的原因是因为 Task.Factory.StartNew
实际上 returns 一个 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);