Почему использование функций, определенных в одном модуле, быстрее, чем функции, определенные в другом? - PullRequest
8 голосов
/ 13 сентября 2011

Рассмотрим этот блок кода:

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

, который вычисляет сумму всех простых чисел ниже миллиона.Для печати результата на моей машине требуется 0,468 секунд.Но если определения isPrime и primes извлекаются в другой модуль, временные затраты составляют 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

Ответы [ 2 ]

7 голосов
/ 13 сентября 2011

Я могу воспроизвести это, если поместить isPrime и primes в разные модули.(Если они находятся в одном и том же модуле, но все еще отделены от main, я не вижу разницы).

Добавление {-# INLINE isPrime #-} возвращает ту же производительность, что и все три в одном модуле, поэтому это будетчто GHC в этом случае нужно было подтолкнуть кросс-модульную вставку.

Это на GHC 7.0.2, Ubuntu 11.04, 64-битная

1 голос
/ 13 сентября 2011

Вы запускаете это внутри GHCi или компилируете через GHC? Я только что попробовал эксперимент, сохранив все определения в одном файле, переместив первые два, и скомпилировав через GHC с включенным и выключенным флагом -O. На моей машине нет заметных различий между различными комбинациями (все они запускаются всего за несколько миллисекунд в течение 1 секунды, используя GHC 7).

...