Параллельные сборы данных в F # - PullRequest
8 голосов
/ 13 марта 2012

Какие из списков, массивов или последовательностей более эффективны для параллельной обработки и могут легко реализовывать параллельные операции, такие как parmap, parfilter и т. Д.?

РЕДАКТИРОВАТЬ: Спасибо запредложения.Array.Parallel выглядит как хороший вариант.Также проверено PSeq.fs, и у меня есть вопрос о том, как работает pmap ниже.

let pmap f xs =
   seq { for x in xs -> async { return f xs } }
   |> Async.Parallel
   |> Async.RunSynchronously

Создается ли новый поток для каждого элемента в последовательности?Если да, есть ли способ разбить seq на куски и создать новое задание для каждого чанка, чтобы он оценивался параллельно?

Я также хотел бы посмотреть, есть ли подобная реализация pmap для списка,Я обнаружил, что Томас имеет ParallelList реализацию в своем блоге здесь .Но я не уверен, что преобразование списка в массив для выполнения параллельной оценки не повлечет за собой слишком много накладных расходов и можно ли этого избежать?

РЕДАКТИРОВАТЬ: Спасибо за все ваши входные данные.Томас ответил на мой первоначальный вопрос.

Отвечая на мой собственный вопрос в первом редактировании:

Я попытался разбить большой список на куски, а затем применить асинхронность к каждому подсписку.

let pmapchunk f xs =
    let chunks = chunk chunksize xs
    seq { for chunk in chunks -> async { return (Seq.map f) chunk } }
    |> Async.Parallel
    |> Async.RunSynchronously
    |> Seq.concat

Результаты: map: 15 с, pmap: 7 с, pmapchunk: 10 с.

Ответы [ 3 ]

9 голосов
/ 13 марта 2012

В библиотеке F # есть параллельная реализация некоторых операций с массивами. В целом, работа с массивами, вероятно, будет наиболее эффективной, если отдельные операции занимают много времени.

  • Посмотрите на модуль Array.Parallel. Он содержит функции для создания массива (init), для выполнения расчетов с элементами (map), а также функцию choose, которую можно использовать для реализации фильтрации.

Если вы пишете сложный конвейер операций, которые довольно просты, но их много, вам нужно использовать PLINQ, который распараллеливает весь конвейер, а не распараллеливает только отдельные операции ( как карта).

  • Посмотрите на модуль PSeq из F # PowerPack для F # дружественной оболочки - она ​​определяет тип pseq<'T> и обычные функции для работы с ними. Это сообщение в блоге также содержит некоторую полезную информацию.
1 голос
/ 13 марта 2012

Наряду с предложением Томаса взглянуть на Array.Parallel, стоит отметить, что массивы (и коллекции на основе массива) всегда будут наиболее эффективными для прохождения (map, iter, ...), потому что они хранятся в непрерывная память.

0 голосов
/ 13 марта 2012

Реально, накладные расходы на переключение типов сбора незначительны по сравнению со стоимостью выполнения асинхронной операции, поэтому тип сбора не имеет значения.

Сказав это, List имеет тенденцию лучше сочетаться с синтаксисом F #, поэтому он может быть лучше

...