E 'un lavoro hack per parVector
, ma questo ha funzionato per me:
import qualified Data.Vector as V
import Control.Parallel.Strategies
import Control.Parallel
import Control.DeepSeq
ack :: Int -> Int -> Int
ack 0 n = n+1
ack m 0 = ack (m-1) 1
ack m n = ack (m-1) (ack m (n-1))
main = do
let vec = V.enumFromN 1 1000
let res = (V.map (ack 2) vec) `using` parVector
print res
parVector :: NFData a => Strategy (V.Vector a)
parVector vec = eval vec `seq` Done vec
where
chunkSize = 1
eval v
| vLen == 0 =()
| vLen <= chunkSize = rnf (v V.! 0) -- FIX this to handle chunks > 1
| otherwise = eval (V.take half v) `par` eval (V.drop half v)
where vLen = V.length v
half = vLen `div` 2
E esecuzione di questo codice:
[[email protected] Test]$ ghc --make -O2 -threaded t.hs
... dumb warning ...
[[email protected] Test]$ time ./t +RTS -N1 >/dev/null
real 0m1.962s user 0m1.951s sys 0m0.009s
[[email protected] Test]$ time ./t +RTS -N2 >/dev/null
real 0m1.119s user 0m2.221s sys 0m0.005s
Quando eseguo il codice con Integer
invece di Int
nel type signature:
[[email protected] Test]$ time ./t +RTS -N2 >/dev/null
real 0m4.754s
user 0m9.435s
sys 0m0.028s
[[email protected] Test]$ time ./t +RTS -N1 >/dev/null
real 0m9.008s
user 0m8.952s
sys 0m0.029s
Rock!
EDIT: E una soluzione che è un po 'più vicino alla vostra precedente tentativo è più pulito (non utilizzare le funzioni da tre moduli separati) e funziona alla grande:
parVector :: NFData a => Strategy (V.Vector a)
parVector vec =
let vLen = V.length vec
half = vLen `div` 2
minChunk = 10
in if vLen > minChunk
then do
let v1 = V.unsafeSlice 0 half vec
v2 = V.unsafeSlice half (vLen - half) vec
parVector v1
parVector v2
return vec
else
evalChunk (vLen-1) >>
return vec
where
evalChunk 0 = rpar (rdeepseq (vec V.! 0)) >> return vec
evalChunk i = rpar (rdeepseq (vec V.! i)) >> evalChunk (i-1)
cose da imparare da questa soluzione:
- Esso utilizza il
Eval
monade, che è stretta così siamo sicuri di suscitare tutto (rispetto ad avvolgere le cose in let
e ricordando di usare modelli Bang).
- Contrariamente a l'implementazione proposto esso (a) non costruisce un nuovo vettore, che è costosa (b) valutazione
evalChunk
forze di ogni elemento utilizzando rpar
e rdeepseq
(non credo rpar vec
forze qualsiasi degli elementi del vettore) .
- Contrariamente a quanto crediamo,
slice
prende un indice e una lunghezza iniziali, non un indice iniziale e finale. Oops!
- Abbiamo ancora bisogno di importare
Control.DeepSeq (NFData)
, ma ho inviato per e-mail l'elenco delle librerie per provare a risolvere il problema.
Le prestazioni sembrano simili alla prima soluzione parVector
in questa risposta, quindi non invierò numeri.
fonte
2010-11-16 17:53:59
È un po 'ansioso che DPH mostri un po' di frutta, vero? –
Beh, una specie di. Mi piacerebbe provare a scrivere codice numerico in Haskell e non capisco ancora cosa dovrei usare per quello. – sastanin
Non penso che la versione di parVector funzioni: 'rseq' non valuterà nessuno degli elementi (è solo WHNF) e' V.concat' è un'operazione O (n) non necessaria - stiamo cercando di forza il calcolo degli elementi, non c'è bisogno di costruire un nuovo vettore. –