다음은 문제가있는 코드의 단순화 된 버전입니다. 콘솔 응용 프로그램에서 실행할 때 예상대로 작동합니다. 모든 쿼리는 병렬로 실행되며 모두 완료되면 Task.WaitAll()
이 반환됩니다.Task.WaitAll ASP.NET에서 대기중인 여러 작업에 걸려있다
그러나이 코드가 웹 응용 프로그램에서 실행되면 요청이 중단됩니다. 디버거를 연결하고 모두 중단하면 실행이 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
중요한주의 사항 중 하나는 Task.WhenAll이 AggregateException을 throw하지 않을 것임을 기다리는 것입니다. 내부 예외 중 하나만 전파됩니다. 전체 AggregateException을 검사하려면 task.WhenAll에서 반환 된 작업에 대한 참조를 저장하고 Exception 속성을 명시 적으로 검사해야합니다. –