F#PSeq.iter, кажется, не использует все ядра

Я выполнял некоторые вычислительные работы в F#. Такие функции, как Array.Parallel.map, использующие.Net Task Parallel Library, экспоненциально ускорили мой код, затрачивая минимум усилий.

Однако из-за проблем с памятью я переделал часть своего кода так, чтобы его можно было лениво вычислять внутри выражения последовательности (, это означает, что мне нужно хранить и передавать меньше информации). Когда пришло время оценить, я использовал:

// processor and memory intensive task, results are not stored
let calculations : seq =  seq {...yield one thing at a time... }

// extract results from calculations for summary data
PSeq.iter someFuncToExtractResults results

вместо :

// processor and memory intensive task, storing these results is an unnecessary task
let calculations : Calculation[] =...do all the things...

// extract results from calculations for summary data
Array.Parallel.map someFuncToExtractResults calculations 

. При использовании любой из функций Array.Parallel я ясно вижу, что все ядра моего компьютера включаются в работу (~100% загрузка ЦП). Однако требуемая дополнительная память означает, что программа никогда не завершалась.

С версией PSeq.iter, когда я запускаю программу, загрузка ЦП составляет всего около 8% (и минимальное использование ОЗУ).

Итак:Есть ли какая-то причина, по которой версия PSeq работает намного медленнее? Это из-за ленивой оценки? Есть ли какой-то волшебный материал «быть параллельным», который мне не хватает?

Спасибо,

Другие ресурсы, реализации исходного кода обоих (кажется, что они используют разные параллельные библиотеки в.NET):

https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/array.fs

https://github.com/fsharp/powerpack/blob/master/src/FSharp.PowerPack.Parallel.Seq/pseq.fs

ИЗМЕНИТЬ :Добавлены дополнительные подробности в примеры кода и подробности

Код:

  • Seq

    // processor and memory intensive task, results are not stored
    let calculations : seq =  
        seq { 
            for index in 0..data.length-1 do
                yield calculationFunc data.[index]
        }
    
    // extract results from calculations for summary data (different module)
    PSeq.iter someFuncToExtractResults results
    
  • Array

    // processor and memory intensive task, storing these results is an unnecessary task
    let calculations : Calculation[] =
        Array.Parallel.map calculationFunc data
    
    // extract results from calculations for summary data (different module)
    Array.Parallel.map someFuncToExtractResults calculations 
    

Details:

  • Хранение версии промежуточного массива выполняется быстро (насколько это происходит до сбоя)менее чем за 10 минут, но использует ~70GB RAM до сбоя (64 ГБ физических данных, остальные страницы)
  • Версия seq занимает более 34 минут и использует часть ОЗУ (всего около 30 ГБ)
  • Я вычисляю ~миллиард значений. Следовательно, миллиард удвоений (по 64 бита каждый )= 7,4505806 ГБ. Есть более сложные формы данных...и несколько ненужных копий, которые я очищаю, отсюда и текущее массовое использование ОЗУ.
  • Да, архитектура не идеальна, ленивое вычисление — это первая часть моей попытки оптимизировать программу и/или разбить данные на более мелкие фрагменты
  • При меньшем наборе данных оба фрагмента кода выводят одно и то же Результаты.
  • @pad, я попробовал то, что вы предложили, PSeq.iter, похоже, работал правильно (все ядра активны)при подаче на вычисление[], но все еще есть проблема с ОЗУ (в конце концов он разбился)
  • как сводная часть кода, так и вычислительная часть интенсивно используют ЦП (в основном из-за больших наборов данных)
  • В версии Seq я просто пытаюсь распараллелить один раз

11
задан Anthony Truskinger 17 April 2012 в 06:35
поделиться