Haskell - параллельная карта, которая уменьшает количество искр

Я хочу написать функцию параллельной карты в Haskell как можно более эффективную. Моя первоначальная попытка, которая, кажется, в настоящее время лучше всего, состоит в том, чтобы просто написать,

pmap :: (a -> b) -> [a] -> [b]
pmap f = runEval . parList rseq . map f
Тем не менее, я не вижу идеального разделения процессоров. Если это возможно связано с количеством искр, могу ли я написать pmap, который делит список на # сегментов cpus, так что создаются минимальные искры? Я попробовал следующее, но показатель (и количество искры) намного хуже,
pmap :: (a -> b) -> [a] -> [b]
pmap f xs = concat $ runEval $ parList rseq $ map (map f) (chunk xs) where
    -- the (len / 4) argument represents the size of the sublists
    chunk xs = chunk' ((length xs) `div` 4) xs
    chunk' n xs | length xs <= n = [xs]
                | otherwise = take n xs : chunk (drop n xs)

Худшая производительность может быть связана с более высоким использованием памяти. Первоначальный pmap немного влияет на 24-ядерные системы, поэтому мне не хватает данных. (Число процессоров на моем рабочем столе - 4, поэтому я просто жестко запрограммировал это).

Изменить 1

Ниже приведены некоторые данные о производительности с помощью +RTS -H512m -N -sstderr -RTS:

Ответ 1

Пакет parallel определяет для вас несколько стратегий параллельной карты:

parMap :: Strategy b -> (a -> b) -> [a] -> [b]

Комбинация parList и карты и конкретная поддержка для разбиения списка:

parListChunk :: Int -> Strategy a -> Strategy [a]

Разделяет список на куски и параллельно применяет стратегию evalList strat к каждому фрагменту.

Вы должны иметь возможность использовать комбинацию из них, чтобы получить любое искрообразование, которое вы желаете. Или, для еще большего контроля, пакет Par monad, для управления количеством созданных потоков (чисто).


Ссылки: документы для папок для параллельного пакета