3

此代码编译并运行没有问题:

module Main where

import Criterion.Main

main :: IO ()
main =
  defaultMain
    [env (return $ [1,2])
         (\is ->
            bgroup "group" (benchmarks is))]

timesTwo :: Int -> Int
timesTwo i = 2 * i

benchmarks :: [Int] -> [Benchmark]
benchmarks is = [ bench "foo" $ nf timesTwo (is !! 0)
                , bench "foo" $ nf timesTwo (is !! 1) ]

但是,如果我将benchmarks功能更改为

benchmarks :: [Int] -> [Benchmark]
benchmarks is = map (\i -> bench "foo" $ nf timesTwo i) is

它仍然可以编译,但我得到这个运行时错误:

ghci> main
*** Exception: Criterion atttempted to retrieve a non-existent environment!
        Perhaps you forgot to use lazy pattern matching in a function which
        constructs benchmarks from an environment?
        (see the documentation for `env` for details)

我该如何解决这个问题?

如您所见,我的目标是映射从环境中获取的列表,以便将其转换为Benchmark可以与 Criterion 一起使用的s列表。

注意:我最终想要使用比两个更多的元素,所以元组不是我想要的。

4

2 回答 2

2

对于不同尺寸的基准测试,我通常会这样做:

module Main (main) where

import Criterion.Main
import System.Random
import Control.Monad

import qualified Data.List
import qualified Data.Sequence

int :: Int -> IO Int
int n = randomRIO (0,n)

benchAtSize :: Int -> Benchmark
benchAtSize n =
    env (replicateM n (int n)) $
    \xs ->
         bgroup (show n)
           [ bench "Data.List"     $ nf Data.List.sort xs
           , bench "Data.Sequence" $ nf (Data.Sequence.sort . Data.Sequence.fromList) xs
           ]

main :: IO ()
main = defaultMain (map benchAtSize [100, 1000, 10000])

env对于确保在同一个样本上比较两个不同的函数很有用,并且它不是为了在运行基准测试之前计算整个数据集而设计的。此外,由于env在对其范围内的任何内容进行基准测试期间,由 by 创建的所有数据都保存在内存中,因此您希望尽可能地减少它,以减少基准测试时的开销。

于 2018-06-06T23:25:48.687 回答
1

env非常挑剔严格。你不能在这里使用它。创建的基准的结构env不能依赖于环境。也就是说,环境可以被正在基准测试的代码使用,但基准测试本身的组织、命名等方式不能使用它。这是因为criterion有时会通过_|_而不是真实环境,当它只想检查基准的结构而不执行它们时。当您使用!!时,基准的组织是手动给出的,即使在以下情况下也是完整的is = _|_

benchmarks _|_ = [ bench "foo" $ nf timesTwo _|_ -- _|_ !! n = _|_; nf is not strict
                 , bench "foo" $ nf timesTwo _|_ ] -- "bench"s are still there

但是map打破了这一点:

benchmarks _|_ = map _etc _|_
               = case _|_ of -- definition of map
                      [] -> []
                      x:xs -> _etc x : map _etc xs
               = _|_ -- benchmark structure gone

你最好的选择就是不使用env

main = do is <- _ -- however you calculate is
          defaultMain $ bgroup "group" $ benchmark is
于 2018-06-06T18:40:30.443 回答