【问题标题】:Detecting misuse of Async/Await: Prevent blocking calls检测 Async/Await 的滥用:防止阻塞调用
【发布时间】:2013-12-25 17:09:04
【问题描述】:

我正在开发一个可扩展的游戏服务器系统,并试图在这个新项目中过度使用 await/async。到目前为止,我设法遇到了几个陷阱。我已经找出了大多数解决方案,并开发了一种“通用实践”来编写异步方法,以便易于检测和避免这些陷阱。不幸的是,以下让我很头疼:

1) 示例:

async Task<int> RunSqlQuery()
{
    DbCommand cmd = conn.CreateCommand();
    ...
    cmd.ExecuteReader();
    ...
}

哇!出于几个原因,这是一种破坏。一,有一个 ExecuteReaderAsync(),可以解决这个问题。其次,此调用将阻塞和停止内部异步框架的工作线程。在桌面环境中不是太重要,但不幸的是,如果您的服务器每秒有 8000 个请求,这可能会严重损害您的性能,并且很难追踪导致问题的精确行。

2) 示例:

void ThisHurts()
{
    someTask.GetAwaiter().GetResult();
}

async Task<int> RunQuery()
{
    ...
    lock(something)
    {
        ThisHurts();
    }
    ...
}

我承认这个看起来有点设计来证明我的观点,但是在处理大量代码时,这是一种难以避免的情况。基本上在锁中调用 await 是致命的。这是一场等待发生的灾难(字面意思)。有很多解释为什么,不管你信不信,它们是真的,构建类似上面的东西,如果你的服务器上有负载并且大量的竞争条件开始链接在一起,你的代码几乎会立即死亡......

所以这个问题是关于如何检测那些错误的 await 用法。有没有像 Resharper 这样的工具(它似乎不支持我想要的大部分内容)。我认为微软应该标记所有非阻塞方法,并强制人们以异步兼容的方式包装它们,或者在尝试在异步方法中调用它们时发出编译器错误。此外,他们可能会强迫您在所有未标记为非阻塞的方法前面添加一个新的“阻塞”关键字,以便您仍然可以使用它们,但会立即显示出耻辱。

到目前为止,我看到的异步框架的主要问题是误用只会在负载过重的情况下出现,这通常很难调试和跟踪,因为它的数据量很大,并且在您附加调试器的那一刻问题就消失了,因为负载消失了。太棒了;)

【问题讨论】:

  • tagged all non-blocking methods and force people to either wrap them in an async compatible way 那是不可能的。如果你有阻塞方法,让它异步的唯一方法是完全重写它以使用非阻塞 IO。
  • 这曾经被称为“设计错误”,之前没有听说过它被称为“灾难”。我想如果你在项目结束时做 TDD。
  • “很难找到导致问题的确切线路。”我不这么认为。 Profilers 可以向您展示您的代码在哪里花费了大量时间。如果你阻塞了很多,你会在那里看到那个方法。
  • 另外,考虑到您不能在lock 中使用await,我发现很难想象情况2 会自然出现的情况。
  • 嗯...不。标记与制作非阻塞无关。它是一个编译器信息,仅此而已。以异步兼容的方式包装是任何方式,所以并非不可能,哈哈。好吧,如果分析器可以区分阻塞和“等待”,那么可以,但到目前为止还没有尝试过。可能会出现第二种情况,因为您可以在锁中等待。只是不在其中,但没有什么可以阻止您在那里调用的 API 等待。

标签: c# .net async-await c#-5.0


【解决方案1】:

该工具仍在围绕asyncawait 开发。在这一点上(2013 年底),我想说我们拥有的不仅仅是最低限度的可行功能。在接下来的几年里,我确实期待更多。

编译器不适合添加此功能;它应该将 C# 转换为 IL,而不是试图强制执行良好的编码实践。它确实执行了可以描述为 C# 语言 一部分的“简单”检查(lock 内没有 await,控制台应用程序没有 async void Main 等)。

编写自己的检查的可能性包括:StyleCop / FxCop / VS 代码分析、NDepend 的 CQL、Re# 插件等。

【讨论】:

    猜你喜欢
    • 2016-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-24
    • 1970-01-01
    • 1970-01-01
    • 2018-05-16
    相关资源
    最近更新 更多