下面是我遇到的代碼的簡化版本。當我在控制檯應用程序中運行它時,它按預期工作。所有查詢均並行運行,並在全部完成時返回Task.WaitAll()
。Task.WaitAll掛在ASP.NET中的多個等待任務中
但是,當此代碼在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;
}
}
}
+1。雖然我會使用術語「請求上下文」而不是「主線程」。 –
@StephenCleary是的,這是有爭議的。我將主線程放在引號中,因爲它不是整個應用程序的主線程,但它可以被認爲是「該請求的主線程」。在我腦海中,這是思考問題的有用方式。 – Servy
一個重要的警告是await Task.WhenAll不會拋出AggregateException;只有一個內部異常會被傳播。如果要檢查整個AggregateException,則需要存儲對task.WhenAll中返回的任務的引用,並明確檢查其Exception屬性。 –