Haskell - параллельная карта, на которой меньше искр - PullRequest
10 голосов
/ 11 мая 2011

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

pmap :: (a -> b) -> [a] -> [b]
pmap f = runEval . parList rseq . map f

Однако я не вижу идеального деления процессора. Если это, возможно, связано с количеством искр, могу ли я написать pmap, которое делит список на # процессорных сегментов, поэтому создаются минимальные искры? Я попробовал следующее, но производительность (и количество искр) намного хуже,

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 Ответ

9 голосов
/ 12 мая 2011

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

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

Сочетание parList и map, а также специальная поддержка разбиения списка:

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

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

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


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

...