[英]Task.WaitAll hanging with multiple awaitable tasks in ASP.NET
下面是我遇到问题的代码的简化版本。 当我在控制台应用程序中运行它时,它按预期工作。 所有查询都是并行运行的, Task.WaitAll()
在完成后都会返回。
但是,当此代码在Web应用程序中运行时,请求才会挂起。 当我附加一个调试器并中断所有时,它表明执行是在Task.WaitAll()
上等待。 第一项任务已经完成,但其他任务从未完成。
我无法弄清楚它在ASP.NET中运行时挂起的原因,但在控制台应用程序中运行良好。
public Foo[] DoWork(int[] values)
{
int count = values.Length;
Task[] tasks = new Task[count];
for (int i = 0; i < count; i++)
{
tasks[i] = GetFooAsync(values[i]);
}
try
{
Task.WaitAll(tasks);
}
catch (AggregateException)
{
// Handle exceptions
}
return ...
}
public async Task<Foo> GetFooAsync(int value)
{
Foo foo = null;
Func<Foo, Task> executeCommand = async (command) =>
{
foo = new Foo();
using (SqlDataReader reader = await command.ExecuteReaderAsync())
{
ReadFoo(reader, foo);
}
};
await QueryAsync(executeCommand, value);
return foo;
}
public async Task QueryAsync(Func<SqlCommand, Task> executeCommand, int value)
{
using (SqlConnection connection = new SqlConnection(...))
{
connection.Open();
using (SqlCommand command = connection.CreateCommand())
{
// Set up query...
await executeCommand(command);
// Log results...
return;
}
}
}
而不是Task.WaitAll
你需要使用await Task.WhenAll
。
在ASP.NET中,您有一个实际的同步上下文。 这意味着在所有await
调用之后,您将被编组回到该上下文以执行延续(有效地序列化这些延续)。 在控制台应用程序中没有同步上下文,因此所有延续都只是发送到线程池。 通过在请求的上下文中使用Task.WaitAll
,您将阻止它,这阻止它被用于处理来自所有其他任务的延续。
另请注意,ASP应用程序中async / await的主要优点之一是不阻止您用于处理请求的线程池线程。 如果你使用Task.WaitAll
你就是在打败那个目的。
进行此更改的一个副作用是,通过从阻塞操作转移到等待操作,异常将以不同方式传播。 它不会抛出AggregateException
,而是抛出一个潜在的异常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.