No creo que una lista sea el tipo de datos correcto para esto. Como solo se trata de una lista vinculada, necesariamente se accederá a los datos secuencialmente. Aunque puede evaluar los elementos en paralelo, no ganará mucho en el paso de reducción. Si realmente necesita una lista, creo que la mejor función sería simplemente
parFold f = foldl1' f . withStrategy (parList rseq)
o tal vez
parFold f = foldl1' f . withStrategy (parBuffer 5 rseq)
Si la etapa de reducción es compleja, es posible obtener una ganancia mediante la subdivisión de la lista como esta:
parReduce f = foldl' f mempty . reducedList . chunkList . withStrategy (parList rseq)
where
chunkList list = let (l,ls) = splitAt 1000 list in l : chunkList ls
reducedList = parMap rseq (foldl' f mempty)
me he tomado la libertad de asumir sus datos es una Monoid
para mempty, si esto no es posible, puede reemplazar mempty con su propio tipo de vacío, o peor caso de uso foldl1'
.
Hay dos operadores de Control.Parallel.Strategies
en uso aquí. El parList
evalúa todos los elementos de la lista en paralelo. Después de eso, el chunkList
divide la lista en fragmentos de 1000 elementos. Cada uno de esos trozos se reduce en paralelo por el parMap
.
También puede intentar
parReduce2 f = foldl' f mempty . reducedList . chunkList
where
chunkList list = let (l,ls) = splitAt 1000 list in l : chunkList ls
reducedList = parMap rseq (foldl' f mempty)
Dependiendo de exactamente cómo se distribuye el trabajo, uno de ellos puede ser más eficiente que los otros.
Si puede usar una estructura de datos que tiene buen soporte para la indexación (Array, Vector, Map, etc.), entonces puede hacer subdivisiones binarias para el paso de reducción, que probablemente será mejor en general.
Como han observado las personas, la lista es una estructura de datos deficiente para la división recursiva en paralelo. Desea algún tipo de estructura binaria de árbol/cuerda, como en el lenguaje Fortress: http://labs.oracle.com/projects/plrg/Publications/ICFPAugust2009Steele.pdf – sclv