为什么Prelude.drop比琐碎的更快?

时间:2018-07-02 14:40:20

标签: haskell optimization singly-linked-list

我做了一些:

main = print $ head . drop (2^30) $ [1..]

-同时使用Prelude.drop和琐碎的drop。 Prelude变体的速度始终快约45%,我不知道为什么。我什至从GHC.List.drop中提取了base-4.11.1.0的定义,但它的表现比我的琐碎代码还差!发生了什么事?

这就是我在做什么:

% stack ghc -- --version           
The Glorious Glasgow Haskell Compilation System, version 8.2.2

Prelude.drop

% git checkout drop-prelude
% git clean --force
% cat ListTest.hs
module Main where

main = print $ head . drop (2^30) $ [1..]
% stack ghc -- ListTest.hs
[1 of 1] Compiling Main             ( ListTest.hs, ListTest.o )
Linking ListTest ...
% time ./ListTest
1073741825
./ListTest  18.76s user 0.09s system 99% cpu 18.906 total

琐碎的drop

% git checkout drop-naive 
% git clean --force
% cat ListTest.hs
module Main where

dropNaive :: Int -> [a] -> [a]
dropNaive 0 xs = xs
dropNaive n [ ] = [ ]
dropNaive n (x: xs) = dropNaive (pred n) xs

main = print $ head . dropNaive (2^30) $ [1..]
% stack ghc -- ListTest.hs
[1 of 1] Compiling Main             ( ListTest.hs, ListTest.o )
Linking ListTest ...
% time ./ListTest
1073741825      
./ListTest  31.56s user 0.12s system 99% cpu 31.774 total

drop来自GHC.List

% git checkout drop-ghc 
% git clean --force
% cat ListTest.hs 
{-# LANGUAGE BangPatterns #-}

module ListTest where

dropGhc :: Int -> [a] -> [a]
{-# INLINE dropGhc #-}
dropGhc n xs
  | n <= 0     = xs
  | otherwise  = unsafeDrop n xs
  where
    unsafeDrop :: Int -> [a] -> [a]
    unsafeDrop !_ []     = []
    unsafeDrop 1  (_:xs) = xs
    unsafeDrop m  (_:xs) = unsafeDrop (m - 1) xs
% cat ListTestRunner.hs 
import ListTest

main = print $ head . dropGhc (2^30) $ [1..]
% stack ghc -- ListTestRunner.hs
[1 of 2] Compiling ListTest         ( ListTest.hs, ListTest.o )
[2 of 2] Compiling Main             ( ListTestRunner.hs, ListTestRunner.o )
Linking ListTestRunner ...
% time ./ListTestRunner
1073741825            
./ListTestRunner  35.35s user 0.14s system 99% cpu 35.591 total

1 个答案:

答案 0 :(得分:3)

我以前犯过这个错误,所以我很怀疑...

您似乎没有在启用优化的情况下进行编译。前奏经过优化编译并链接到其中,因此当您使用前奏的drop时,会隐式使用优化代码。本地复制(将常量从2^30减少到2^25之后-没有理由让自己等待那么长时间),启用优化会导致dropGhc和序言drop具有相同的含义时间,dropNaive并没有明显恶化。 dropGhcdropNaive之间的措词略有不同,可能会对生成的代码产生微妙的影响;我对一个人为什么会比另一个人好没有很好的直觉。

还要注意,base是一个特殊的软件包,因为它是ghc的构建过程的一部分,是使用其自身的构建系统而不是由Cabal像普通软件包那样构建的。正如@sjakobi在评论中指出的,there is a setting in ghc's build configurationbase的优化级别设置为O2

相关问题