Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
简单Haskell性能分析_Haskell - Fatal编程技术网

简单Haskell性能分析

简单Haskell性能分析,haskell,Haskell,我试图比较在二元搜索树中查找第n个最小数的两种实现的性能。这只是一个玩具学习问题。我天真的测量尝试如下: getNth :: Tree Int -> Int -> Either String Int eval :: [Either b Int] -> Int eval = (foldl (+) 0) . rights main :: IO () main = do let t = foldl treeInsertBalanced EmptyTree [1..1000

我试图比较在二元搜索树中查找第n个最小数的两种实现的性能。这只是一个玩具学习问题。我天真的测量尝试如下:

getNth :: Tree Int -> Int -> Either String Int

eval :: [Either b Int] -> Int
eval = (foldl (+) 0) . rights

main :: IO ()
main = do
    let t = foldl treeInsertBalanced EmptyTree [1..1000000]
        first = getNth t 100000
        iterations = 100000000000
        second = take iterations $ repeat $ getNth t 100
        third = take iterations $ repeat $ getNth' t 100

    print $ "dummy to cause eval: " ++ (show first)
    print ""

    time1 <- System.CPUTime.getCPUTime
    print $ eval second
    time2 <- System.CPUTime.getCPUTime
    print $ eval third
    time3 <- System.CPUTime.getCPUTime

    let secondTime = time2-time1
        thirdTime  = time3-time2
        timeDiff   = secondTime - thirdTime
    print $ "take version = " ++ (show secondTime)
    print $ "opt version  = " ++ (show thirdTime)
    print $ "diff         = " ++ (show timeDiff)
getNth::Tree Int->Int->任一字符串Int
eval::[b Int]->Int
eval=(foldl(+)0)。权利
main::IO()
main=do
设t=foldl树insertbalanced EmptyTree[1..1000000]
第一个=第n个t 100000
迭代次数=10000000000
第二次=迭代次数$repeat$getNth t 100
第三次=迭代次数$repeat$getNth't 100
打印$“dummy以引起评估:”++(先显示)
打印“”
时间1(可在

一些意见:

  • 强制求值的一个好方法是使用
    Control.deepseq
    中的
    deepseq

  • repeat
    不会重新计算其参数

  • GHC非常擅长发现相同的表达式,因此有时您必须用相同的参数隐藏函数调用,以使GHC重新评估函数调用

  • 下面是使用
    deepseq
    的示例:

     import Control.DeepSeq (deepseq)
     import Control.Monad
     import Debug.Trace
     import System.TimeIt
     import System.Environment
    
     theList = [1..8] ++ [undefined] ++ [10] :: [Int]
    
     main1 = do
       print $ length theList
       print $ deepseq theList (length theList)
    
    第一个
    print
    语句发出
    10
    。第二个抛出异常,因为
    deepseq
    调用试图计算
    undefined
    元素

    <> >查看<代码>重复>代码>不重新评估它的参数,考虑这个例子:

     foo = repeat $ trace "(here)" 2
    
     main2 = print $ take 3 foo
    
    运行
    main2
    的结果是:

    [(here)
    2,2,2]
    
    所发生的事情是,当调用
    foo
    的头以执行
    repeat
    时,对其参数求值。这将调用
    跟踪
    ,该跟踪打印
    (此处)
    ,并返回2。当需要列表的其余部分时,
    foo
    通过
    repeat
    保存此值

    最后,这里演示了GHC在发现具有相同参数的函数调用方面有多么出色

     fib :: Int -> Int
     fib 0 = 0
     fib 1 = 1
     fib n = fib (n-1) + fib (n-2)
    
     theN = 34  -- use 24 if running under ghci
    
     compute1 = fib theN
     compute2 k = fib theN
     compute3 k = fib (k+theN-k)
    
    fib然后
    只是一个函数调用,需要一段时间来计算(大约0.6秒)

    一些结论:

    • compute1
      这样的顶级表达式被存储
    • 如果不使用-O2,添加一个被忽略的参数(例如,
      compute2
      )将欺骗GHC重新计算函数调用
    • 对于-O2,可能需要一种更巧妙的方法来伪装函数调用,以使GHC在循环中重新评估它

    考虑使用基准测试包,如Criteria。
     loop1 n = forM_ [1..n] $ \_ -> print compute1
     loop2 n = forM_ [1..n] $ \k -> print (compute2 k)
     loop3 n = forM_ [1..n] $ \k -> print (compute3 k)
    
     timeLoop loop = do timeIt $ loop 1
                        timeIt $ loop 2
                        timeIt $ loop 3
                        timeIt $ loop 10
    
     main4 = timeLoop loop1
     main5 = timeLoop loop2
     main6 = timeLoop loop3
    
     main = do (arg:_) <- getArgs
               case arg of
                 "4" -> main4
                 "5" -> main5
                 "6" -> main6
    
             w/o -O2    with -O2
    main4     1 secs    0.1 sec
    main5    13 secs    0.1 sec
    main6    13 secs    1.0 sec