What is causing this particular method to deadlock?

我与影子孤独终老i 提交于 2021-02-16 05:28:40

问题


As best as I can, I opt for async all the way down. However, I am still stuck using ASP.NET Membership which isn't built for async. As a result my calls to methods like string[] GetRolesForUser() can't use async.

In order to build roles properly I depend on data from various sources so I am using multiple tasks to fetch the data in parallel:

public override string[] GetRolesForUser(string username) {
   ...
   Task.WaitAll(taskAccounts, taskContracts, taskOtherContracts, taskMoreContracts, taskSomeProduct);
   ...
}

All of these tasks are simply fetching data from a SQL Server database using the Entity Framework. However, the introduction of that last task (taskSomeProduct) is causing a deadlock while none of the other methods have been.

Here is the method that causes a deadlock:

public async Task<int> SomeProduct(IEnumerable<string> ids) {
    var q = from c in this.context.Contracts

            join p in this.context.Products
            on c.ProductId equals p.Id

            where ids.Contains(c.Id)

            select p.Code;

    //Adding .ConfigureAwait(false) fixes the problem here
    var codes = await q.ToListAsync();
    var slotCount = codes .Sum(p => char.GetNumericValue(p, p.Length - 1));

    return Convert.ToInt32(slotCount);
}

However, this method (which looks very similar to all the other methods) isn't causing deadlocks:

public async Task<List<CustomAccount>> SomeAccounts(IEnumerable<string> ids) {
    return await this.context.Accounts
        .Where(o => ids.Contains(o.Id))
        .ToListAsync()
        .ToCustomAccountListAsync();
}

I'm not quite sure what it is about that one method that is causing the deadlock. Ultimately they are both doing the same task of querying the database. Adding ConfigureAwait(false) to the one method does fix the problem, but I'm not quite sure what differentiates itself from the other methods which execute fine.

Edit

Here is some additional code which I originally omitted for brevity:

public static Task<List<CustomAccount>> ToCustomAccountListAsync(this Task<List<Account>> sqlObjectsTask) {
    var sqlObjects = sqlObjectsTask.Result;
    var customObjects = sqlObjects.Select(o => PopulateCustomAccount(o)).ToList();
    return Task.FromResult<List<CustomAccount>>(customObjects);
}

The PopulateCustomAccount method simply returns a CustomAccount object from the database Account object.


回答1:


In ToCustomAccountListAsync you call Task.Result. That's a classic deadlock. Use await.




回答2:


This is not an answer, but I have a lot to say, it wouldn't fit in comments.

Some fact: EF context is not thread safe and doesn't support parallel execution:

While thread safety would make async more useful it is an orthogonal feature. It is unclear that we could ever implement support for it in the most general case, given that EF interacts with a graph composed of user code to maintain state and there aren't easy ways to ensure that this code is also thread safe.

For the moment, EF will detect if the developer attempts to execute two async operations at one time and throw.

Some prediction: You say that:

The parallel execution of the other four tasks has been in production for months without deadlocking.

They can't be executing in parallel. One possibility is that the thread pool cannot assign more than one thread to your operations, in that case they would be executed sequentially. Or it could be the way you are initializing your tasks, I'm not sure. Assuming they are executed sequentially (otherwise you would have recognized the exception I'm talking about), there is another problem:

Task.WaitAll hanging with multiple awaitable tasks in ASP.NET

So maybe it isn't about that specific task SomeProduct but it always happens on the last task? Well, if they executed in parallel, there wouldn't be a "last task" but as I've already pointed out, they must be running sequentially considering they had been in production for quite a long time.



来源:https://stackoverflow.com/questions/25252930/what-is-causing-this-particular-method-to-deadlock

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!