[Haskell-beginners] parallel quicksort
Ovidiu Deac
ovidiudeac at gmail.com
Wed Aug 3 09:21:23 CEST 2011
Meanwhile I found this chapter
http://book.realworldhaskell.org/read/concurrent-and-multicore-programming.html
which discusses exactly the parallelization of the quicksort
algorithm.
Also this http://stackoverflow.com/questions/2338850/haskell-as-a-highly-concurrent-server
which has links to some resources for parallel haskell.
On Wed, Aug 3, 2011 at 1:44 AM, Ovidiu Deac <ovidiudeac at gmail.com> wrote:
> I'm trying to write a parallel quicksort algorithm for lists.
>
> This is my original implementation:
>
> quickSort [] = []
> quickSort (x:xs) = (quickSort small) ⊕ [x] ⊕ (quickSort big)
> where
> small = [p | p ← xs, p ≤ x]
> big = [p | p ← xs, p > x]
>
> and the output is:
>
> $ ghc -threaded -rtsopts -o quicksort quicksort.hs && ./quicksort +RTS -N2 -RTS
> [1 of 1] Compiling Main ( quicksort.hs, quicksort.o )
> Linking quicksort ...
> Sorting 1000000 elements...
> CPU Time: 13290000000000
> Time elapsed: 8.929503s
>
> ovidiu at asus:~/work/haskell$ ghc -threaded -rtsopts -o quicksort
> quicksort.hs && ./quicksort +RTS -N2 -RTS
> Sorting 1000000 elements...
> CPU Time: 11240000000000
> Time elapsed: 7.785293s
>
> ovidiu at asus:~/work/haskell$ ghc -threaded -rtsopts -o quicksort
> quicksort.hs && ./quicksort +RTS -N1 -RTS
> Sorting 1000000 elements...
> CPU Time: 6790000000000
> Time elapsed: 6.817648s
>
> ovidiu at asus:~/work/haskell$ ghc -threaded -rtsopts -o quicksort
> quicksort.hs && ./quicksort +RTS -N1 -RTS
> Sorting 1000000 elements...
> CPU Time: 6980000000000
> Time elapsed: 7.006658s
>
> ovidiu at asus:~/work/haskell$ ghc -threaded -rtsopts -o quicksort
> quicksort.hs && ./quicksort +RTS -N1 -RTS
> Sorting 1000000 elements...
> CPU Time: 5900000000000
> Time elapsed: 5.932236s
>
> ...so the conclusion is that using option N1 is faster the N2. This makes sense.
>
> Then I tried to parallelize it:
>
> First try:
> -----------------
> quickSort [] = []
> quickSort (x:xs) = small `pseq` ((quickSort small) ⊕ [x] ⊕ (quickSort big))
> where
> small = [p | p ← xs, p ≤ x]
> big = [p | p ← xs, p > x]
>
> $ ghc -threaded -rtsopts -o quicksort quicksort.hs && ./quicksort +RTS -N2 -RTS
> [1 of 1] Compiling Main ( quicksort.hs, quicksort.o )
> Linking quicksort ...
> Sorting 1000000 elements...
> CPU Time: 12020000000000
> Time elapsed: 8.29653s
>
> This is slower then the non-parallel version
>
> Second try:
> ---------------
> quickSort [] = []
> quickSort (x:xs) = small `par` ((quickSort small) ⊕ [x] ⊕ (quickSort big))
> where
> small = [p | p ← xs, p ≤ x]
> big = [p | p ← xs, p > x]
>
> $ ghc -threaded -rtsopts -o quicksort quicksort.hs && ./quicksort +RTS -N2 -RTS
> Sorting 1000000 elements...
> CPU Time: 14750000000000
> Time elapsed: 10.772271s
>
> Even slower
>
> Third try:
> -------------
> quickSort [] = []
> quickSort (x:xs) = small `par` (big `par` ((quickSort small) ⊕ [x] ⊕
> (quickSort big)))
> where
> small = [p | p ← xs, p ≤ x]
> big = [p | p ← xs, p > x]
>
> $ ghc -threaded -rtsopts -o quicksort quicksort.hs && ./quicksort +RTS -N2 -RTS
> [1 of 1] Compiling Main ( quicksort.hs, quicksort.o )
> Linking quicksort ...
> Sorting 1000000 elements...
> CPU Time: 134490000000000
> Time elapsed: 122.917093s
>
> Fourth try:
> ------------------------
> quickSort [] = []
> quickSort (x:xs) = small `par` (big `pseq` ((quickSort small) ⊕ [x] ⊕
> (quickSort big)))
> where
> small = [p | p ← xs, p ≤ x]
> big = [p | p ← xs, p > x]
>
> $ ghc -threaded -rtsopts -o quicksort quicksort.hs && ./quicksort +RTS -N2 -RTS
> [1 of 1] Compiling Main ( quicksort.hs, quicksort.o )
> Linking quicksort ...
> Sorting 1000000 elements...
> CPU Time: 12770000000000
> Time elapsed: 8.844304s
> -----------------------------
>
> It seems that I'm unable to make it parallel. What am I doing wrong?
>
> Thanks,
> ovidiu
>
>
> See the full code below:
> --------------------------------------------------
> module Main where
>
> import Prelude
> import Data.List
> import Data.Time.Clock
> import System.CPUTime
> import System.Random
> import Control.Parallel
> import Control.Exception (evaluate)
> import Control.DeepSeq (rnf)
> import Text.Printf
>
> quickSort [] = []
> quickSort (x:xs) = small `par` (big `par` ((quickSort small) ⊕ [x] ⊕
> (quickSort big)))
> where
> small = [p | p ← xs, p ≤ x]
> big = [p | p ← xs, p > x]
>
> randomlist :: Int → StdGen → [Int]
> randomlist n = take n∘unfoldr (Just∘random)
>
> len = 10 ↑ 6
>
> time = do
> t ← getCurrentTime
> c ← getCPUTime
> return (t,c)
>
> measure f p = do
> (t1, c1) ← time
> evaluate $ rnf $ f p
> (t2, c2) ← time
> return (diffUTCTime t2 t1, c2 - c1)
>
> main = do
> seed ← newStdGen
> let rs = randomlist len seed
>
> printf "Sorting %d elements...\n" len
>
>
> (t, cpu) ← measure quickSort rs
> printf "CPU Time: %dλnTime elapsed: %sλn" cpu (show t)
>
More information about the Beginners
mailing list