“避免在编译器热路径中分配”Roslyn 编码约定

Posted

技术标签:

【中文标题】“避免在编译器热路径中分配”Roslyn 编码约定【英文标题】:"Avoid allocations in compiler hot paths" Roslyn Coding Conventions 【发布时间】:2014-05-18 15:51:21 【问题描述】:

我一直在阅读 .NET 编译器平台(“Roslyn”)的 Contributing Code 部分,并且遇到了编码约定的指南。我了解大多数编码约定以及他们为什么会要求它。但我不明白他们的意思:

避免在编译器热路径中分配:

避免使用 LINQ。

避免对没有结构枚举器的集合使用 foreach。

什么是“编译器热路径”?为什么我应该避免使用 LINQ 并避免对没有结构枚举器的集合执行 foreach?

【问题讨论】:

【参考方案1】:

Compiler hot paths 是编译器中的代码执行路径,其中大部分执行时间都花费在其中,并且可能会非常频繁地执行。

在这些代码路径中避免(堆)分配的原因是分配可能会触发垃圾收集,这可能会导致突然的、极端的性能下降。这些显然应该在非常常用的代码路径中避免。

Linq 和 foreach 被单独列出,因为它们会隐式分配内存 - 除非您的 GetEnumerator 返回 struct,这不会导致堆分配。

【讨论】:

垃圾收集无关紧要,因为编译器是一个总执行时间很重要的应用程序,实际上是多次调用的平均执行时间。在 UI 应用程序中,垃圾收集导致的减速很重要,用户甚至可以将 1/10 秒的延迟视为卡顿。代码路径中的分配仅意味着 许多 分配,您应该避免进行 许多 分配,因为它们平均需要时间。 @gnasher729:Roslyn 一个 UI 应用程序; GC 活动直接影响 VS 中的打字速度。 @gasher729 在不触发收集的 GC 上进行堆分配几乎不需要任何时间。否则,大多数操作严重依赖堆分配的 GC 语言在实践中将无法工作。哦,还有 SLaks 所说的。 @Manu343726 哦,我同意。只要有足够的备用内存(以相当大的因素),GC 实际上工作得非常好,而且您不在实时系统上。在内存密集型应用程序中(或者相反,在内存受限的系统上),现代 GC 的性能并不好。 gnasher729 部分正确;我们在 Roslyn 代码库中担心的只是部分突然的、极端的性能恶化。我们同样关心编译器的吞吐量。最小化分配可以减少垃圾回收的数量,从而提高编译器的吞吐量。【参考方案2】:

“热路径”是对性能最关键的代码路径。每秒执行数百万或数十亿次的代码的 sn-ps,占用了大部分执行时间。

在我阅读时,其他两个只是可能导致隐式分配的情况示例,因此在代码的性能关键部分应避免使用。

【讨论】:

以上是关于“避免在编译器热路径中分配”Roslyn 编码约定的主要内容,如果未能解决你的问题,请参考以下文章

Net中的代码规范工具及使用

什么是“按约定编码”?

使用基于Roslyn的编译时AOP框架来解决.NET项目的代码复用问题

如何在使用 svn 生成差异时忽略编码约定/样式?

翻译 | QML编码约定

编码约定:将后端与前端标签匹配