说你的函数永远不应该被内联有什么好处?

Sup*_*tar 6 inline swift

我很了解 Swift 的内联。我知道四个函数内联属性之间的细微差别。我使用了@inline(__always)很多,尤其是当我只是制作这样的含糖 API 时:

public extension String {
    @inline(__always)
    var length: Int { count }
}
Run Code Online (Sandbox Code Playgroud)

我这样做是因为内联它实际上并不涉及成本,但如果不内联,就会产生额外的堆栈帧的成本。对于不太明显的糖,我会根据需要倾向于@inlinable和/或。@usableFromInline

然而,有一个区别令我烦恼。两个可能的参数@inlinenever__always。尽管缺乏实际的文档,但这里的这种拼写选择充当了一种自我文档的作用,这意味着如果您要使用其中一个,您应该倾向于never, 并且__always不鼓励这样做。

但为什么这是 Swift 语言设计者鼓励的方向呢?据我所知,如果根本没有应用任何属性,那么这就是行为:

  • 如果一个函数(等)在声明它的模块中使用,编译器可能会选择内联或不内联它,这取决于哪个会产生更好的代码(通过某种措施)
  • 如果该函数(等)在模块外部使用,则其实现不会以允许内联的方式公开,因此它永远不会被内联。

所以,似乎大多数时候,非内联是默认的。这很好,很花花公子,表面上我对此没有任何问题;不要使可执行文件超出您的需要。

但话说回来,我从来没有理由认为@inline(never)它有用。据我了解,我使用的唯一原因@inline(never)是如果我注意到 Swift 编译器选择内联过多的非注释函数,并且它使我的可执行文件膨胀。这似乎是一个超级小众的现象:

  1. 我的软件运行良好
  2. Swift 编译器用于决定是否内联某些内容的算法没有为我的代码做出正确的选择
  3. 我非常关心二进制文件的大小,以至于我仔细检查它以发现函数自动内联太多
  4. 问题仅出在我编写到自己的模块中的代码中;不是我从其他模块使用的代码

或者,正如Rob在评论中 所说,如果您正在经历一些反汇编,那么自动内联会使其难以阅读。

我无法想象这些是 Swift 语言设计者在设计这个属性时所考虑的用例。特别是由于 Swift 不适用于嵌入式系统,因此二进制大小(以及一般的(反)汇编)并不是真正值得关注的问题。无论如何,我从未见过过大的 Swift 二进制文件(>50MB)。

那么为什么never鼓励多呢__always我经常遇到为什么应该强制内联函数的原因,但我还没有看到强制函数堆叠的原因,至少在我自己的工作中是这样。