I'm trying to use Task.WaitAll
on a list of tasks. The thing is the tasks are an async lambda which breaks Tasks.WaitAll
as it never waits.
我正在尝试在任务列表中使用Task.WaitAll。事情是任务是一个异步lambda,它打破Tasks.WaitAll,因为它永远不会等待。
Here is an example code block:
这是一个示例代码块:
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
This doesn't wait because of the async lambda. So how am I supposed to await I/O operations in my lambda?
这不会因为异步lambda而等待。那我该如何等待我的lambda中的I / O操作呢?
4 个解决方案
#1
15
Task.Factory.StartNew
doesn't recognise async
delegates as there is no overload that accepts a function returning a Task
.
Task.Factory.StartNew无法识别异步委托,因为没有重载接受返回任务的函数。
This plus other reasons (see StartNew is dangerous) is why you should be using Task.Run
here:
这加上其他原因(参见StartNew是危险的)是你应该在这里使用Task.Run的原因:
tasks.Add(Task.Run(async () => ...
#2
14
This doesn't wait because of the async lambda. So how am I supposed to await I/O operations in my lambda?
这不会因为异步lambda而等待。那我该如何等待我的lambda中的I / O操作呢?
The reason Task.WaitAll
doesn't wait for the completion of the IO work presented by your async lambda is because Task.Factory.StartNew
actually returns a Task<Task>
. Since your list is a List<Task>
(and Task<T>
derives from Task
), you wait on the outer task started by StartNew
, while ignoring the inner one created by the async lambda. This is why they say Task.Factory.StartNew
is dangerous with respect to async.
Task.WaitAll不等待异步lambda提供的IO工作完成的原因是因为Task.Factory.StartNew实际上返回了Task
How could you fix this? You could explicitly call Task<Task>.Unwrap()
in order to get the inner task:
你怎么能解决这个问题?您可以显式调用Task
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());
Or like others said, you could call Task.Run
instead:
或者像其他人说的那样,你可以调用Task.Run:
tasks.Add(Task.Run(async () => /* lambda */);
Also, since you want to be doing things right, you'll want to use Task.WhenAll
, why is asynchronously waitable, instead of Task.WaitAll
which synchronously blocks:
此外,既然你想做正确的事情,你会想要使用Task.WhenAll,为什么是异步等待,而不是同步阻止的Task.WaitAll:
await Task.WhenAll(tasks);
#3
0
You can do like this.
你可以这样做。
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...
}
}
#4
-1
you have to use the Task.ContinueWith
method. Like this
你必须使用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...
});
}
}
}
#1
15
Task.Factory.StartNew
doesn't recognise async
delegates as there is no overload that accepts a function returning a Task
.
Task.Factory.StartNew无法识别异步委托,因为没有重载接受返回任务的函数。
This plus other reasons (see StartNew is dangerous) is why you should be using Task.Run
here:
这加上其他原因(参见StartNew是危险的)是你应该在这里使用Task.Run的原因:
tasks.Add(Task.Run(async () => ...
#2
14
This doesn't wait because of the async lambda. So how am I supposed to await I/O operations in my lambda?
这不会因为异步lambda而等待。那我该如何等待我的lambda中的I / O操作呢?
The reason Task.WaitAll
doesn't wait for the completion of the IO work presented by your async lambda is because Task.Factory.StartNew
actually returns a Task<Task>
. Since your list is a List<Task>
(and Task<T>
derives from Task
), you wait on the outer task started by StartNew
, while ignoring the inner one created by the async lambda. This is why they say Task.Factory.StartNew
is dangerous with respect to async.
Task.WaitAll不等待异步lambda提供的IO工作完成的原因是因为Task.Factory.StartNew实际上返回了Task
How could you fix this? You could explicitly call Task<Task>.Unwrap()
in order to get the inner task:
你怎么能解决这个问题?您可以显式调用Task
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());
Or like others said, you could call Task.Run
instead:
或者像其他人说的那样,你可以调用Task.Run:
tasks.Add(Task.Run(async () => /* lambda */);
Also, since you want to be doing things right, you'll want to use Task.WhenAll
, why is asynchronously waitable, instead of Task.WaitAll
which synchronously blocks:
此外,既然你想做正确的事情,你会想要使用Task.WhenAll,为什么是异步等待,而不是同步阻止的Task.WaitAll:
await Task.WhenAll(tasks);
#3
0
You can do like this.
你可以这样做。
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...
}
}
#4
-1
you have to use the Task.ContinueWith
method. Like this
你必须使用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...
});
}
}
}