Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
545 views
in Technique[技术] by (71.8m points)

c# - Task.WaitAll hanging with multiple awaitable tasks in ASP.NET

Below is a simplified version of the code I'm having trouble with. When I run this in a console application, it works as expected. All queries are run in parallel and Task.WaitAll() returns when they are all complete.

However, when this code runs in a web application, the request just hangs. When I attach a debugger and break all, it shows that execution is wait on Task.WaitAll(). And the first task has completed, but the others never finish.

I can't figure out why it hangs when running in ASP.NET, but works fine in a console application.

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;
        }
    }           
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Rather than Task.WaitAll you need to use await Task.WhenAll.

In ASP.NET you have an actual synchronization context. This means that after all await calls you will be marshaled back to that context to execute the continuation (effectively serializing these continuations). In a console app there is no synchronization context, so all of the continuations are just sent to the thread pool. By using Task.WaitAll in the request's context you're blocking it, which is preventing it from being used to handle the continuations from all of the other tasks.

Also note that one of the primary benefits of async/await in an ASP app is to not block the thread pool thread that you're using to handle the request. If you use a Task.WaitAll you're defeating that purpose.

A side effect of making this change is that by moving from a blocking operation to an await operation exceptions will be propagated differently. Rather than throwing AggregateException it will throw one of the underlying exceptions.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...