Rozważmy następujący fragment kodu:Dlaczego korzystanie z funkcji zdefiniowanych w tym samym module jest szybsze niż ta sama funkcja zdefiniowana w innym?
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
który oblicza sumę wszystkich liczb pierwszych poniżej jednego miliona. Potrwa to 0.468 sekund, aby wydrukować wynik na moim komputerze. Ale jeśli definicje isPrime
i primes
są wyodrębniane do innego modułu, koszt czasu wynosi 1,23 sekund, jest prawie 3 razy wolniejszy.
Oczywiście mogę kopiować/wklejać wszystkie wymagane obszary, ale jestem również ciekawy, dlaczego tak się dzieje i jak go rozwiązać.
[Edytuj] Używam GHC 7.0.3 (Windows 7 + MinGW). Kod jest zapisany w EclipseFP (używa Scion jako back-end IDE) i wbudowany w plik wykonywalny z flagami -O2
.
Próbowałem też budowania pakietu poza 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
Oto wynik:
$ 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
to działa! Dzięki! – claude
GHC wykona bardzo agresywną inline w module, szczególnie jeśli funkcja, która ma być wbudowana, nie jest eksportowana. O wiele mniej chętnie inline funkcje na granicach modułów, chyba że INLINE je ręcznie. –