比如何时使用SPECIALIZE
pragma 以及它有什么性能提升。
如果你有一个(类型类)多态函数,你让编译器专门化一个函数,并期望它经常在类的一个或几个实例上被调用。
专业化删除了使用它的字典查找,并且通常可以进一步优化,类成员函数通常可以被内联,并且它们受到严格性分析,两者都可能带来巨大的性能提升。如果唯一可能的优化是消除字典查找,那么收益通常不会很大。
从 GHC-7 开始,给函数一个{-# INLINABLE #-}
pragma 可能更有用,这使得它的(几乎没有改变,执行一些规范化和去糖)源在接口文件中可用,所以函数可以被专门化,甚至可能内联在呼叫站点。
在哪里使用RULES
。我听说人们正在考虑不触发的特定规则?我们如何检查?
您可以使用-ddump-rule-firings
命令行选项检查触发了哪些规则。这通常会转储大量已触发的规则,因此您必须搜索一下您自己的规则。
你使用规则
当您对特殊类型的函数有更高效的版本时,例如
{-# RULES
"realToFrac/Float->Double" realToFrac = float2Double
#-}
当某些函数可以替换为特殊参数的更有效版本时,例如
{-# RULES
"^2/Int" forall x. x ^ (2 :: Int) = let u = x in u*u
"^3/Int" forall x. x ^ (3 :: Int) = let u = x in u*u*u
"^4/Int" forall x. x ^ (4 :: Int) = let u = x in u*u*u*u
"^5/Int" forall x. x ^ (5 :: Int) = let u = x in u*u*u*u*u
"^2/Integer" forall x. x ^ (2 :: Integer) = let u = x in u*u
"^3/Integer" forall x. x ^ (3 :: Integer) = let u = x in u*u*u
"^4/Integer" forall x. x ^ (4 :: Integer) = let u = x in u*u*u*u
"^5/Integer" forall x. x ^ (5 :: Integer) = let u = x in u*u*u*u*u
#-}
当根据一般规律重写表达式时可能会产生更好优化的代码,例如
{-# RULES
"map/map" forall f g. (map f) . (map g) = map (f . g)
#-}
后一种风格的广泛使用RULES
在融合框架中,例如在text
库中,对于 中的列表函数,使用规则实现base
了不同类型的融合(融合)。foldr/build
什么时候使函数的参数严格,什么时候有帮助?我知道使参数严格会使参数被评估为正常形式,那么为什么我不应该对所有函数参数添加严格性呢?我该如何决定?
使参数严格将确保它被评估为弱头范式,而不是范式。
您不要使所有参数都严格,因为某些函数的某些参数必须是非严格的才能工作,而如果所有参数都严格,有些函数的效率会降低。
例如,它的第二个参数必须是非严格的,才能在无限列表上工作,更一般地说,每个函数在第二个参数中必须 是非严格的,才能在无限列表上工作。在有限列表上,在第二个参数中使用 non-strict 函数可以显着提高效率 ( )。partition
foldr
foldr (&&) True (False:replicate (10^9) True)
如果您知道必须先评估该论点,然后才能完成任何有价值的工作,那么您就可以使论点变得严格。在很多情况下,GHC 的严格度分析器可以自己完成,但当然不是全部。
一个非常典型的情况是循环或尾递归中的累加器,其中增加严格性可以防止在途中构建巨大的 thunk。
我不知道在哪里增加严格的硬性规则,对我来说这是一个经验问题,一段时间后你就会知道在哪些地方增加严格可能有帮助,在哪里有害。
根据经验,对小数据(如Int
)进行评估是有意义的,但也有例外。
如何查看和检查我的程序中是否存在空间泄漏?构成空间泄漏的一般模式是什么?
第一步是使用该+RTS -s
选项(如果该程序已启用 rtsopts 链接)。这显示了总体使用了多少内存,并且您通常可以判断您是否有泄漏。通过使用该选项运行程序可以获得更多信息输出,该+RTS -hT
选项生成一个可以帮助定位空间泄漏的堆配置文件(此外,该程序需要与启用的 rtsopts 链接)。
如果需要进一步分析,则需要在启用分析的情况下编译程序(-rtsops -prof -fprof-auto
在较旧的 GHC 中,该-fprof-auto
选项不可用,该-prof-auto-all
选项是那里最接近的对应关系)。
然后使用各种分析选项运行它并查看生成的堆配置文件。
空间泄漏的两个最常见原因是
第三位可能是不需要的共享,GHC 几乎没有消除常见的子表达式,但它偶尔会共享长列表,即使在不需要的地方也是如此。
为了找到泄漏的原因,我再次知道没有硬性规定,有时,可以通过在一个地方增加严格性或在另一个地方增加惰性来修复泄漏。
如何查看是否存在懒惰过多的问题?我总是可以检查堆分析,但我想知道懒惰伤害的一般原因、例子和模式是什么?
通常,在可以逐步建立结果的情况下需要惰性,而在处理完成之前无法交付任何结果的情况下不需要惰性,例如在左折叠或通常在尾递归函数中。