我已阅读有关Vector
使用现代优化技术的库并尝试将其性能与列表进行比较。下面的代码生成一些类似声音的数据(这对我的学科领域很重要)并对结果求和:
import System.Environment (getArgs)
import System.TimeIt
import Data.List
import Data.Vector.Unboxed as V
x1 :: Int -> [Double]
x1 n = [1..(fromIntegral n)]
x2 :: Int -> V.Vector Double
x2 n = V.enumFromN 1 n
osc1 f = Prelude.map (\x -> sin(2*pi*x*f/44100.0))
osc2 f = V.map (\x -> sin(2*pi*x*f/44100.0))
sum1 = Data.List.foldl1' (+)
sum2 = V.foldl1' (+)
zip1 = Prelude.zipWith (+)
zip2 = V.zipWith (+)
main = do s <- getArgs
let n = read (s !! 0) :: Int
print "Prelude version"
timeIt $ print $ sum1 $ zip1 (osc1 55.5 (x1 n)) (osc1 110.0 $ x1 n)
print "Vector version"
timeIt $ print $ sum2 $ zip2 (osc2 55.5 (x2 n)) (osc2 110.0 $ x2 n)
在带有 vector0.10.0.1 和 timeit1.0.0.0 的 win7 上运行的 GHC 7.6.3 给了我这些结果:
c:\coding>test 10000000
"Prelude version"
90.98579564908658
CPU time: 9.92s
"Vector version"
90.98579564908658
CPU time: 11.03s
Vector 版本甚至有点慢Unboxed
,盒装 Vector 版本需要 22.67 秒。为什么会这样?我应该如何编写此代码以获得最大性能?
UPD。添加-O2
(**)后,我对结果更加清楚。看起来盒装向量更难融合。
List Vector.Unboxed Vector
ghc test.hs 9.78 10.94 21.95
ghc test.hs -O2 3.39 1.25 7.57
(**) 我没有注意到,因为即使命令行标志不同,ghc 也不会重新编译未更改的文件,而且-O2
在注意到这一点之前我实际上并没有运行版本。对不起