简体   繁体   English

在async / await上阻塞主线程

[英]blocking main thread on async/await

I am trying to make my base repository class asynchronous and I am running into some trouble. 我试图让我的基础存储库类异步,我遇到了一些麻烦。 I am using Dapper ORM in my C# application. 我在我的C#应用​​程序中使用Dapper ORM。

Base method 基本方法

protected async Task<List<T>> Read<T>(CommandDefinition cmd) {
    using(SqlConnection myCon = new SqlConnection(Config.DBConnection)) {
        await myCon.OpenAsync();

        IEnumerable<T> results = await myCon.QueryAsync<T>(cmd);

        List<T> retVal = results.ToList();

        myCon.Close();

        return retVal;
    }
}

Calling method 通话方式

public List<Category> GetAllActiveCategories(Guid siteGuid) {
    return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid).Result;
}

Everything looks in order to me. 一切都看起来对我来说。 I have the method declaration decorated with the async keyword. 我有使用async关键字修饰的方法声明。 I am awaiting on asynchronous methods. 我正在等待异步方法。

The problem that I am having is that the thread blocks on await myCon.OpenAsync(); 我遇到的问题是线程阻塞await myCon.OpenAsync(); . This is my first attempt at using async and await, so I am sure that I am doing something wrong, but it is not obvious. 这是我第一次尝试使用async和await,所以我确信我做错了什么,但这并不明显。 Please help! 请帮忙!

The posted Read code is fine. 发布的阅读代码很好。 The issue is in the consuming code. 问题出在消费代码中。 It's common to get a deadlock with async if you call Wait() or Result on the returned Task or its antecedent Task up in the call chain. 如果在返回的Task上调用Wait()Result或在调用链中调用其先行Task ,则通常会遇到async死锁。

As always in these cases, the general advice applies: don't block on async code . 在这些情况下,一般建议都适用: 不要阻止异步代码 Once you start using async/await , you should be using async/await throughout your entire call chain. 一旦开始使用async/await ,就应该在整个调用链中使用async/await

So, your calling method becomes 所以,你的调用方法就变成了

public Task<List<Category>> GetAllActiveCategoriesAsync(Guid siteGuid) {
    return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid);
}

... or ... 要么

public async Task<List<Category>> GetAllActiveCategoriesAsync(Guid siteGuid) {
    List<Category> result = await base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid);

    // Do something.

    return result;
}

The culprit is: 罪魁祸首是:

return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid).Result;

As Kirill noted, any time you use .Wait() or .Result on a Task, you are blocking synchronously. 正如Kirill所指出的,无论.Result在任务中使用.Wait().Result ,都会同步阻塞。 What you need to do is this: 你需要做的是:

public Task<List<Category>> GetAllActiveCategories(Guid siteGuid) {
    return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid);
}

This will return a Task to the calling method of this method, and so on... it has to be async "all the way up". 这将把一个Task返回给这个方法的调用方法,依此类推......它必须是异步“一直向上”。

If the top-level consumer of this code is ASP.NET, you're fine. 如果此代码的顶级使用者是ASP.NET,那么你很好。 Just return a Task<IActionResult> (or the appropriate return type wrapped in a Task) and the framework will sort out the await ing for you. 只需返回一个Task<IActionResult> (或包含在Task中的相应返回类型),框架将为您排序await

If you're writing a console application or otherwise can't make it "async all the way up", you'll have to either block on .Result or make your method async void and use await . 如果您正在编写控制台应用程序或无法使其“一直异步”,则必须阻止.Result或使您的方法async void并使用await Neither one is a great solution, sadly. 遗憾的是,这两个都不是一个很好的解决方案。 Async/await is pretty aggressive in the sense that you really do have to use it throughout your stack. Async / await非常具有攻击性,因为你真的必须在整个堆栈中使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM