2012-01-13 30 views
8

Paralel olarak kullanmak istediğim bir frequencyBy işlevim var. Ben paralel frequencyBy yılında map çalıştırmak istiyorumHaskell'de Paralel Stratejiler Nasıl Kullanılır

import Control.Parallel.Strategies 
import Control.DeepSeq 
import System.Environment 

frequencyBy :: (a -> b -> Bool) -> [a] -> [b] -> [(a,Int)] 
frequencyBy f as bs = map 
    (\a ->(a, foldr (\b -> if f a b then (+) 1 else id) 0 bs)) as 

main :: IO() 
main = do 
    x:xs <- getArgs 
    let result = frequencyBy (==) [1::Int .. 10000] [1 .. (read x)] `using` 
       parList rdeepseq 
    print $ product $ map snd $ result 

: Burada basit bir test durumda izler. Bunu parList rdeepseq kullanarak (main'daki diğer tüm öğeler, yalnızca her şeyin en iyi duruma getirilmediğinden emin olmak için) kullanmaya çalışıyorum. Ancak, bu işe yaramıyor, iki iş parçacığı aynı anda iki iş parçacığı kadar çalışır. Burada ne yapıyorum anlamadım.

+3

İki iş parçacığı aynı anda tek bir iş parçacığının iki katı kadar iş yaparsa, bunun düzgün bir şekilde paralel olması anlamına gelmez mi? – ehird

cevap

9

Bu yükün ne kadar büyük olduğunu x; eğer her kıvılcımda yaptığınız iş, her kıvılcımı üretmek için gereken süreye eşdeğer ise (ve tabii ki, zamanlama yükü, vb.), o zaman problemlerle karşılaşırsınız.

parListChunk, örn. parListChunk 64 rdeepseq; Hangi chunk boyutunun kullanılacağını anlamaya çalışmalısınız. Mevcut stratejiniz, listenin tüm öğeleri için bir kıvılcım oluştururken, parListChunk, listedeki belirli bir boyuttaki her yığın için bir kıvılcım oluşturur ve bu öbek öğesinin her öğesi için sırayla belirttiğiniz stratejiyi kullanır.

Bu arada, frequencyBy'daki foldr, muhtemelen aşırı sersemlik oluşturma nedeniyle işleri yavaşlatıyor; Bu sorunu gidermek için

.

Elbette, her zaman olduğu gibi, -O2 ile derlediğinizden ve +RTS -N ile çalıştığınızdan emin olun.

+0

Bu, aynı kod değil; OP'nin işlevi 'toplamına eşdeğerdir. map (const 1) $ filtre (f a) bs' veya 'length $ filter (f a) bs', benim için bir gelişme olmamasına rağmen (ve' length 'kullanımı çok daha yavaş). –

+0

'parListChunk 2 rdeepseq' zaten hile yapar ve yalnızca iki iş parçacığı üzerinde (bir iş parçacığına kıyasla) yalnızca yarım zaman aldığından emin olur. Bu durum garip gelmekle birlikte, 1'in parçalarının mükemmel bir parazitlemeye yol açmasına neden olurken, neden 1'in parçalarını çok fazla yüke maruz bırakacaktı? – user362382

+0

Toplam kullandım. map (const 1) $ filter (f a) bs' önce, ama el ile bunu bir 'foldr'de birleştirmenin daha hızlı olduğunu öğrendim. – user362382

7

Bence paralellik çok ince taneli. parList, her öğeyi paralel olarak değerlendirmeye çalışır ve gerçekten tek bir öğe için o kadar çok iş yoktur.

parList'dan parListChunk 500'a değiştirdiğimde, yürütme süresi neredeyse% 50 artar; Bende olduğu kadar iyi bir çift çekirdekli makinede olduğum gibi.

Referans için, x=20000 ile test ediyordum.