为什么使用在同一模块中定义的函数比在另一个模块中定义的函数更快?

cla*_*ude 8 optimization haskell modularity module

考虑这段代码:

isPrime primes' n = foldr (\p r -> p * p > n || (n `rem` p /= 0 && r)) True primes'

primes = 2 : filter (isPrime primes) [3..]

main = putStrLn $ show $ sum $ takeWhile (< 1000000) primes
Run Code Online (Sandbox Code Playgroud)

它计算低于一百万的所有素数之和.在我的机器上打印结果需要0.468秒.但如果定义isPrimeprimes被提取到另一个模块,时间成本是1.23秒,它几乎慢3倍.

当然,我可以在任何需要的地方复制/粘贴定义,但我也很好奇为什么会发生这种情况,以及如何解决它.


[编辑] 我正在使用GHC 7.0.3(Windows 7 + MinGW).代码是用EclipseFP编写的(它使用Scion作为IDE后端),并内置到带有-O2标志的可执行文件中.

我也尝试在IDE之外构建包:

executable test
  hs-source-dirs:  src
  main-is:         Main.hs
  build-depends:   base >= 4
  ghc-options:     -O2
  other-modules:   Primes

executable test2
  hs-source-dirs:  src2
  main-is:         Main.hs
  build-depends:   base >= 4
  ghc-options:     -O2
Run Code Online (Sandbox Code Playgroud)

这是结果:

$ time test/test
37550402023

real    0m1.296s
user    0m0.000s
sys     0m0.031s

$ time test2/test2
37550402023

real    0m0.520s
user    0m0.015s
sys     0m0.015s
Run Code Online (Sandbox Code Playgroud)

ham*_*mar 7

如果我把isPrimeprimes放在不同的模块中,我可以重现这个.(如果它们在同一个模块中,但仍然分开main,我认为没有区别).

添加{-# INLINE isPrime #-}回报与将所有三个模块放在一个模块中的性能相同,因此在这种情况下,GHC似乎需要轻推进行跨模块内联.

这是在GHC 7.0.2,Ubuntu 11.04,64位

  • GHC将在模块内执行非常激进的内联,特别是如果不导出要内联的函数.除非您手动将它们内联,否则不太希望跨模块边界内联函数. (5认同)