Haskell:不能使用getCPUTime

Gmp*_*Gmp 4 benchmarking haskell lazy-evaluation

我有:

main :: IO ()
main = do
     iniciofibonaccimap <- getCPUTime
     let fibonaccimap = map fib listaVintesete
     fimfibonaccimap <- getCPUTime
     let difffibonaccimap = (fromIntegral (fimfibonaccimap - iniciofibonaccimap)) / (10^12)
     printf "Computation time fibonaccimap: %0.3f sec\n" (difffibonaccimap :: Double)

listaVintesete :: [Integer]
listaVintesete = replicate 100 27

fib :: Integer -> Integer
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)
Run Code Online (Sandbox Code Playgroud)

*Main> main
Computation time fibonaccimap: 0.000 sec
Run Code Online (Sandbox Code Playgroud)

我不明白为什么会这样.帮帮我谢谢.

Mik*_*son 7

哈斯克尔很懒.您在行中请求的计算

let fibonaccimap = map fib listaVintesete
Run Code Online (Sandbox Code Playgroud)

直到你以某种方式使用的价值才真正发生fibonaccimap.因此,要测量使用的时间,您需要引入一些会强制程序执行实际计算的东西.

ETA:我最初建议打印最后一个元素来强制评估.正如TomMD所指出的那样,这远不够好 - 我强烈建议在这里阅读他的回答,以实际处理这一特定代码的方式.


Tho*_*son 7

正如其他人所说,这是由于懒惰的评价.要强制评估,您应该使用deepseq包并BangPatterns:

{-# LANGUAGE BangPatterns #-}
import Control.DeepSeq
import Text.Printf
import System.CPUTime

main :: IO ()
main = do
 iniciofibonaccimap <- getCPUTime
 let !fibonaccimap = rnf $ map fib listaVintesete
 fimfibonaccimap <- getCPUTime
 let difffibonaccimap = (fromIntegral (fimfibonaccimap - iniciofibonaccimap)) / (10^12)
 printf "Computation time fibonaccimap: %0.3f sec\n" (difffibonaccimap :: Double)
...
Run Code Online (Sandbox Code Playgroud)

在上面的代码中你应该注意三件事:

  1. 它编译(模块化...您在上面定义的函数).当您发布问题代码时,请确保它运行(哇,您应该包含导入)
  2. 使用rnf来自deepseq.这会强制评估列表中的每个元素.
  3. 爆炸模式开启!fibonaccimap,意思是"现在就做,不要等待".这会强制列表被评估为弱头正常形式(whnf,基本上只是第一个构造函数(:)).如果没有这个,这个rnf功能本身就会没有评估.

导致:

$ ghc --make ds.hs
$ ./ds
Computation time fibonaccimap: 6.603 sec
Run Code Online (Sandbox Code Playgroud)

如果您打算进行基准测试,您还应该使用optimization(-O2)和Criterion包而不是getCPUTime.