Entity Framework 6 - 强制使用异步查询,编译时防止同步调用。

4
在升级到EF6.1后,我们的目标是充分利用异步/等待选项与数据集进行交互。在从以前的Linq2Sql移植中,有许多.ToList(),.FirstOrDefault()和.Count()。我知道我们可以搜索并修复这些问题,但如果我们能够在编译时防止这些函数被允许进入构建,那就更好了。是否有创造性的想法来实现这一点?即使只是编译器警告也可以(例如使用Obsolete属性)。

使用基于Roslyn的分析器应该很简单。 - Stephen Cleary
只是想让您知道,在99%的情况下,异步数据库调用是无意义的,甚至对项目有害:https://dev59.com/ml8f5IYBdhLWcg3wD_Av#25087273 和 https://dev59.com/eGcs5IYBdhLWcg3wgkMQ#12796711 - usr
在我们的环境中,我们的API位于IIS下,其中线程池线程非常宝贵。我们遇到过一些(可扩展性)情况,由于请求的数量,IIS缺乏线程。大多数调用正在等待DB查询返回或磁盘数据读取,导致IIS在等待释放线程时排队请求。有人会说“只需添加更多线程”,但这不是我们想要采取的方法。转向异步任务是我们决定采取的措施,到目前为止(时间会证明),我们没有遇到任何问题。 - TravisWhidden
1
好的。也许你是对的,但可能正确的答案是将最小线程设置为500,然后完成。如果排队的请求超过这个数量,无论使用哪种后端(db / 磁盘),后端都无法处理它。但从你的描述来看,边缘情况下似乎可以考虑使用异步操作 :) 你是否考虑过将最热门的查询设置为异步,其余的则保留同步?这似乎是更好的权衡。异步会影响代码质量。 - usr
1
重点是不要有500个线程,每个线程使用1兆内存,并在CPU上创建大量争用。这不是可扩展的方法。通过同时使用一些异步和同步,您仍然会遇到相同的问题。通过强制实施异步模型(我的最初的问题),您鼓励/强制开发人员使用最适合可扩展性而不是开发便利性的模式。即使是人类认为“快速”的查询(即100毫秒),在一次阻塞该线程x 1000个用户的情况下,意味着您将更快地耗尽线程池。顺便说一句,这不是毒药 - 它是优雅的。 - TravisWhidden
异步比仅仅增加线程数量更好的想法。如果您仍然希望减轻数据库服务器的负载,最好限制可能与其同时连接的数量。使用异步可以很好地解决这个问题,因为它在等待时不会占用线程。无论如何,唯一真正的解决方案是测试并查看结果。这在很大程度上取决于服务器配置和硬件。 - Mikael Eliasson
2个回答

0

您可以使用.NET编译器平台编写一个诊断和代码修复程序,以查找这些模式并提供警告/错误。

您甚至可以实现语法转换来自动更改这些结构 - 虽然这样做的工作量可能比手动操作更大。


是的,我考虑过Roslyn,或者老派的FXCop,但学习它们可能需要更长的时间。如果我想要编译时警告或错误,那可能是唯一的选择。 - TravisWhidden

0

接着上一篇文章...我没有找到一个可以在编译时检测到这个问题的解决方案,但是我能够在DataContext中通过代码实现:

        public EfMyCustomContext(string connctionString)
        : base(string.Format(CONNECTION_STRING, connctionString))
    {
#if DEBUG
        this.Database.Log = LogDataBaseCall;
#endif
    }

#if DEBUG
        private void LogDataBaseCall(string s)
        {
            if (s.Contains("Executing "))
            {
                if (!s.Contains("asynchronously"))
                {
                    // This code was not executed asynchronously
                    // Please look at the stack trace, and identify what needs
                    // to be loaded. Note, an entity.SomeOtherEntityOrCollection can be loaded
                    // with the eConnect API call entity.SomeOtherEntityOrCollectionLoadAsync() before using the 
                    // object that is going to hit the sub object. This is the most common mistake
                    // and this breakpoint will help you identify all synchronous code. 
                    // eConnect does not want any synchronous code in the code base.
                    System.Diagnostics.Debugger.Break();
                }
            }
        }
#endif

希望这能帮助到其他人,但仍然希望在编译期间有一些选项。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接