我一直在F#做一些计算密集型的工作。功能如 Array.Parallel.map
使用.Net任务并行库已经以指数方式加快了我的代码,实现了非常小的努力。
但是,由于内存问题,我重新编写了我的代码的一部分,以便可以在序列表达式中进行延迟评估(这意味着我必须存储并传递较少的信息)。到时候评估我使用的:
// processor and memory intensive task, results are not stored
let calculations : seq<Calculation> = 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函数时,我可以清楚地看到计算机上的所有核心都开始运转(CPU使用率约为100%)。但是,所需的额外内存意味着程序永远不会完成。
在运行程序时使用PSeq.iter版本,CPU使用率仅为8%(并且RAM使用率最低)。
那么:有没有什么理由说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<Calculation> = 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
排列
// 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
细节:
- 存储中间阵列版本在10分钟内快速运行(在崩溃之前),但在崩溃之前使用~70GB RAM(64GB物理,其余分页)
- seq版本需要34分钟并使用一小部分RAM(仅约30GB)
- 我正在计算出数十亿的价值。因此,十亿双打(每个64位)= 7.4505806GB。还有更复杂的数据形式......还有一些不必要的副本,我正在清理当前大量的RAM使用情况。
- 是的,架构不是很好,懒惰的评估是我尝试优化程序和/或将数据批量分成较小块的第一部分
- 使用较小的数据集,两个代码块都会输出相同的结果。
- @pad,我尝试了你的建议,PSeq.iter似乎正常工作(所有核心都处于活动状态),当计算[]时,但仍然存在RAM问题(它最终崩溃)
- 代码的汇总部分和计算部分都是CPU密集型的(主要是因为大型数据集)
- 使用Seq版本我只想实现一次并行化