【问题标题】:Entity Framework 6 - Enforce asynchronous queries, compile time prevent synchronous callsEntity Framework 6 - 强制异步查询,编译时防止同步调用
【发布时间】:2015-08-07 20:04:35
【问题描述】:

随着迁移到 EF6.1,我们的目标是使用独占性的 Async/Await 选项与我们的数据集对话。从我们之前的 Linq2Sql 移植时,有许多 .ToList()、.FirstOrDefault() 和 .Count()。我知道我们可以搜索并修复所有这些,但如果我们能够在编译时阻止这些函数甚至被允许进入构建,那就太好了。有没有人对如何实现这一点有创意?即使它们是可能抛出的编译器警告(例如使用 Obsolete 属性)。

【问题讨论】:

  • 使用基于Roslyn 的分析器应该非常简单。
  • 只是想让您知道,在 99% 的情况下,异步数据库调用没有实际意义,甚至对项目有害:stackoverflow.com/a/25087273/122718stackoverflow.com/a/12796711/122718
  • 在我们的环境中,我们的 API 位于 IIS 下,其中线程池线程非常有价值。我们遇到了由于进入的请求数量而导致 IIS 缺乏线程的情况(可扩展性)。大多数调用正在等待 DB 查询返回,或者要读取磁盘数据导致 IIS 在等待线程被释放时对请求进行排队.有人会说“只是添加更多线程”,但这不是我们想要采取的方法。迁移到异步任务是我们决定要做的事情,到目前为止(时间会证明),我们还没有遇到任何问题。
  • 好的。也许你是对的,但可能正确的答案是将最小线程数设置为 500 并完成。如果你有更多的队列,无论你使用什么后端(db/disk),后端都无法处理它。但是从您的描述来看,使用异步是有意义的:)您是否考虑过使最热门的查询异步并让其余查询保持同步?似乎是一个更好的权衡。异步是代码质量的毒药。
  • 关键是不要有 500 个线程,每个线程使用 1 兆内存,并在 CPU 上产生很多争用。这不是一种可扩展的方法。通过一些异步和一些同步,您仍然会遇到相同的问题。通过强制执行异步模型(我最初的问题),您鼓励/强制您的开发人员使用为可伸缩性设计的最佳模式,而不是易于开发。即使是查询人类事物“快”(即 100 毫秒),一次阻塞该线程 x 1000 个用户,也意味着您将更快地耗尽您的线程池。顺便说一句,它不是毒药——它很优雅。

标签: c# .net entity-framework asynchronous entity-framework-6


【解决方案1】:

您可以使用.NET Compiler Platform 编写Diagnostic and Code Fix,它将查找这些模式并提供警告/错误。

您甚至可以实现语法转换来自动更改这些结构 - 尽管这项工作可能比手工完成更昂贵。

【讨论】:

  • 是的,确实考虑过 Roslyn,或者一个老派的 FXCop,但学习需要更长的时间。如果我想要编译时警告或错误,那可能是唯一的选择。
【解决方案2】:

跟进此...我从未找到可以在编译时检测到此问题的解决方案,但我能够在 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

希望这对其他人有帮助,如果在编译期间有一些选项,我仍然会喜欢。

【讨论】:

    猜你喜欢
    • 2014-01-04
    • 1970-01-01
    • 2017-03-18
    • 2015-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多