有啥理由不对函数使用 INLINABLE pragma 吗?

Posted

技术标签:

【中文标题】有啥理由不对函数使用 INLINABLE pragma 吗?【英文标题】:Is there any reason not to use the INLINABLE pragma for a function?有什么理由不对函数使用 INLINABLE pragma 吗? 【发布时间】:2012-03-31 09:01:45 【问题描述】:

documentation 声明:

函数 f 上的 -# INLINABLE f #- pragma 具有以下行为:

当 INLINE 表示“请内联我”时,INLINABLE 表示“随意内联我;请自行决定”。换句话说,选择权留给了 GHC,它使用与 pragma-free 函数相同的规则。与 INLINE 不同,该决定是在调用站点做出的,因此会受到内联阈值、优化级别等的影响。

与 INLINE 一样,INLINABLE pragma 保留原始 RHS 的副本以用于内联目的,并将其保留在接口文件中,而不管 RHS 的大小。

使用 INLINABLE 的一种方法是与特殊函数 inline 结合使用(第 7.18 节,“特殊内置函数”)。调用 inline f 非常努力地内联 f。为了确保 f 可以内联,最好将 f 的定义标记为 INLINABLE,以便 GHC 保证无论它有多大都会暴露展开。此外,通过将 f 注释为 INLINABLE,您可以确保 f 的原始 RHS 是内联的,而不是 f GHC 优化器生成的任何随机优化版本。

INLINABLE pragma 也适用于 SPECIALISE:如果您将函数 f 标记为 INLINABLE,那么您随后可以在另一个模块中进行 SPECIALIZE(参见第 7.16.8 节,“SPECIALIZE pragma”)。

与 INLINE 不同,可以在递归函数上使用 INLINABLE pragma。这样做的主要原因是允许以后使用 SPECIALISE

它有什么缺点?

它会使接口文件变得更大、更大吗?它会使编译速度变慢吗?

我有什么理由不应该在我编写的每个导出函数上加上一个 INLINABLE 编译指示? GHC 是否有任何理由不在我编写的每个导出函数上放置一个 INLINABLE pragma?

【问题讨论】:

【参考方案1】:

使用 INLINABLE 和完全不使用 pragma 有三个区别:

没有 INLINABLE,接口文件中的定义是优化后的代码,而使用 INLINABLE,它是您编写的代码(或多或少)。特别是,如果没有 INLINABLE,GHC 可能会将其他函数内联到函数的定义中。

如果没有 INLINABLE,如果接口文件太大,GHC 将忽略接口文件中的定义。如果其他一些函数被内联到右侧,这很容易将其推到极限。

INLINABLE 还开启了一些巧妙的机制,这些机制会在使用它们的地方自动专门化重载函数,并与其他模块共享专门版本,这些模块可传递导入创建专门版本的模块。

李>

【讨论】:

我正在尝试了解实际后果。第一点是否意味着函数没有内联,它将使用未优化的代码并且速度较慢?或者如果它确实被内联但 RULES 没有触发,它会变慢吗?还是会根据具体情况有时更快,有时更慢?关于第二点,除了磁盘空间之外,将其包含在接口文件中是否有任何缺点?它们会变得如此之大以至于成为问题(磁盘很大)吗?并且回复:第三点,有什么理由它不是未经修饰的商品吗?它会导致大量有问题的代码膨胀吗? 我故意避免谈论实际影响,因为在大多数情况下我不确定 :-) 我说服 Simon PJ 添加 INLINABLE 因为我想要一个不会造成太多影响的 INLINE 变体代码膨胀,通过使用 GHC 已经非常复杂的关于何时内联的启发式算法。要回答您的第一个问题:不,还会有一个编译到原始模块中的函数的优化版本(与 INLINE 一样),这将用于未内联的调用。在接口中包含大量函数定义会减慢速度。 嗯,好的。有一些关于何时使用它和何时不使用它的指南会很好,但我想我必须进行实验。 :) 我知道这个问题很老,但我只想问一个问题以确保我理解您的答案:这是否意味着使用 INLINABLE 与不使用它相比,唯一的缺点是减慢编译时间或增加接口文件的大小? 再做一次尝试:如果我们生活在一个每个函数都自动获得一个 INLINABLE pragma 的世界里,那有什么不好呢?

以上是关于有啥理由不对函数使用 INLINABLE pragma 吗?的主要内容,如果未能解决你的问题,请参考以下文章

使用 INLINABLE pragma 的缺点

有啥理由重载全局新建和删除?

有啥理由将代码放在 Python 中的文档字符串之前?

有啥理由不使用“受保护”的属性吗?

有啥理由不使用 JSONP?

使用 if(1 || !Foo()) 有啥理由吗?