Haskell:矩阵排序比矢量排序慢得多

时间:2016-08-10 19:21:25

标签: performance sorting haskell matrix

我必须在Haskell中对大整数矩阵的行进行排序,然后我开始使用随机数据进行基准测试。我发现Haskell比C ++慢3倍。

由于随机性,我希望行比较总是在第一列终止(它应该没有重复)。因此,我将矩阵缩小为实现为Vector(Unboxed.Vector Int)的单个列,并将其排序与通常的Vector Int进行比较。

Vector Int和C ++一样快(好消息!),但同样,列矩阵慢了3倍。你知道为什么吗?请找到以下代码。

import qualified Data.Vector.Unboxed as UV(Vector, fromList)
import qualified Data.Vector as V(Vector, fromList, modify)
import Criterion.Main(env, bench, nf, defaultMain)
import System.Random(randomIO)
import qualified Data.Vector.Algorithms.Intro as Alg(sort)

randomVector :: Int -> IO (V.Vector Int)
randomVector count = V.fromList <$> mapM (\_ -> randomIO) [1..count]

randomVVector :: Int -> IO (V.Vector (UV.Vector Int))
randomVVector count = V.fromList <$> mapM (\_ -> do
                                               x <- randomIO
                                               return $ UV.fromList [x]) [1..count]

benchSort :: IO ()
benchSort = do
  let bVVect = env (randomVVector 300000) $ bench "sortVVector" . nf (V.modify Alg.sort)
      bVect = env (randomVector 300000) $ bench "sortVector" . nf (V.modify Alg.sort)
  defaultMain [bVect, bVVect]

main = benchSort

2 个答案:

答案 0 :(得分:1)

根据dfeuer的建议,将矢量矢量实现为ArrayArray#比Vector(Unboxed.Vector Int)快4倍,比排序c ++ std::vector<std::vector<int> >慢40%:

import Control.Monad.Primitive
import Data.Primitive.ByteArray
import qualified Data.Vector.Generic.Mutable.Base as GM(MVector(..))
import GHC.Prim

data MutableArrayArray s a = MutableArrayArray (MutableArrayArray# s)

instance GM.MVector MutableArrayArray ByteArray where
  {-# INLINE basicLength #-}
  basicLength (MutableArrayArray marr) = I# (sizeofMutableArrayArray# marr)

  {-# INLINE basicUnsafeRead #-}
  basicUnsafeRead (MutableArrayArray marr) (I# i) = primitive $ \s -> case readByteArrayArray# marr i s of
    (# s1, bar #) -> (# s1, ByteArray bar #)

  {-# INLINE basicUnsafeWrite #-}
  basicUnsafeWrite (MutableArrayArray marr) (I# i) (ByteArray bar) = primitive $ \s ->
    (# writeByteArrayArray# marr i bar s, () #)

例如,对整数矩阵进行排序将使用

sortIntArrays :: ByteArray -> ByteArray -> Ordering
sortIntArrays x y = let h1 = indexByteArray x 0 :: Int
                        h2 = indexByteArray y 0 :: Int in
                    compare h1 h2

答案 1 :(得分:1)

正如Edward Kmett向我解释的那样,Haskell版本有一个额外的间接层。 UV.Vector看起来像

data Vector a = Vector !Int !Int ByteArray#

因此,向量向量中的每个条目实际上是指向保存切片索引的记录的指针和指向字节数组的指针。这是C ++代码没有的额外间接。解决方案是使用ArrayArray#,它是一个直接指向字节数组或进一步ArrayArray#的数组。如果您需要vector,您必须弄清楚如何处理切片机械。另一个选择是切换到primitive,它提供更简单的数组。