2011-09-13 33 views
8

考慮的代碼塊:爲什麼使用在同一模塊中定義的函數比在另一個模塊中定義的函數更快?

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 

,其計算低於1百萬的所有質數的和。這需要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 

這裏的結果:

$ 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 

回答

7

我可以重現這個,如果我把isPrimeprimes在不同的模塊。 (如果它們在同一模塊中,但仍與main分開,我看不出有什麼區別)。

添加{-# INLINE isPrime #-}的性能與所有三合一模塊的性能相同,因此在這種情況下,看起來GHC需要微調來進行跨模塊內聯。

這是GHC 7.0.2,Ubuntu的11.04,64位

+0

它的工作原理!謝謝! – claude

+5

GHC將在模塊中執行非常積極的內聯,特別是如果內聯函數未被導出。除非您手動將它們聯機,否則它不太渴望跨模塊邊界內聯函數。 –

1

你裏面GHCI運行此或通過GHC編譯?我只是嘗試了一個實驗,將所有定義保存在同一個文件中,將前兩個移出,並通過GHC編譯-O標誌。我的機器上的不同組合之間沒有明顯差異(使用GHC 7,所有組合在1秒內只運行幾毫秒)。

+0

你使用'-O'或'-O2'?恕我直言,許多優化可能會受到代碼運動的影響,由第二個標誌觸發。 – fuz

+0

建立環境信息添加到原來的文章,謝謝! – claude

+0

@FUZxxl我實際上都嘗試過。兩種情況都沒有明顯的差異。總體執行速度最快的是沒有傳遞給GHC的優化標誌,但我們正在討論在我的機器上的所有cobminations之間執行時間約100毫秒的整體傳播。 –

相關問題