阅读了 Stack Overflow 上的问题 Using vectors for performance improvement in Haskell,介绍了在 Haskell 中快速实现原地快速排序的方法后,我给自己设定了两个目标:
对于1,000,000个元素的向量,我得到了以下结果:
使用中位数三取样来避免对预排序向量的性能影响,实现相同的算法;
制作并行版本。
以下是结果(为了简化,留下了一些小细节):
import qualified Data.Vector.Unboxed.Mutable as MV
import qualified Data.Vector.Generic.Mutable as GM
type Vector = MV.IOVector Int
type Sort = Vector -> IO ()
medianofthreepartition :: Vector -> Int -> IO Int
medianofthreepartition uv li = do
p1 <- MV.unsafeRead uv li
p2 <- MV.unsafeRead uv $ li `div` 2
p3 <- MV.unsafeRead uv 0
let p = median p1 p2 p3
GM.unstablePartition (< p) uv
vquicksort :: Sort
vquicksort uv = do
let li = MV.length uv - 1
j <- medianofthreepartition uv li
when (j > 1) (vquicksort (MV.unsafeSlice 0 j uv))
when (j + 1 < li) (vquicksort (MV.unsafeSlice (j+1) (li-j) uv))
vparquicksort :: Sort
vparquicksort uv = do
let li = MV.length uv - 1
j <- medianofthreepartition uv li
t1 <- tryfork (j > 1) (vparquicksort (MV.unsafeSlice 0 j uv))
t2 <- tryfork (j + 1 < li) (vparquicksort (MV.unsafeSlice (j+1) (li-j) uv))
wait t1
wait t2
tryfork :: Bool -> IO () -> IO (Maybe (MVar ()))
tryfork False _ = return Nothing
tryfork True action = do
done <- newEmptyMVar :: IO (MVar ())
_ <- forkFinally action (\_ -> putMVar done ())
return $ Just done
wait :: Maybe (MVar ()) -> IO ()
wait Nothing = return ()
wait (Just done) = swapMVar done ()
median :: Int -> Int -> Int -> Int
median a b c
| a > b =
if b > c then b
else if a > c then c
else a
| otherwise =
if a > c then a
else if b > c then c
else b
对于1,000,000个元素的向量,我得到了以下结果:
"Number of threads: 4"
"**** Parallel ****"
"Testing sort with length: 1000000"
"Creating vector"
"Printing vector"
"Sorting random vector"
CPU time: 12.30 s
"Sorting ordered vector"
CPU time: 9.44 s
"**** Single thread ****"
"Testing sort with length: 1000000"
"Creating vector"
"Printing vector"
"Sorting random vector"
CPU time: 0.27 s
"Sorting ordered vector"
CPU time: 0.39 s
我的问题如下:
- 为什么使用预排序的向量性能仍在下降?
- 为什么使用forkIO和四个线程无法提高性能?
par
而不是forkIO
。有关更多详细信息,请参见parallel
包此处。 - Gabriella Gonzalezpar
的效果对应物是Par
monad,它是monad-par
包的一部分,你可以在这里找到它。请查看Control.Monad.Par.IO
模块。 - Gabriella Gonzalez