实践小记,不求详尽。解决方案限制为用R、R的C扩展或第三方扩展包。
计算问题:对于一个规模为10W*100的双精度矩阵A,计算A*t(A)并对每一行取前10个{zd0}的值,结果为一个10W*10的矩阵。
正常的解法:直接计算A*t(A),得到一个10W*10W的矩阵,对每一行作sort,然后取A[, 1:10],问题是10W*10W这个临时矩阵太庞大,一般内存都容不下,也没有必要放一下那么大的临时数据。
C扩展的解决方案:写一个C的底层扩展,计算出结果矩阵的每一行时,马上作sort,然后只保留前10个{zd0}的值,其它的丢弃,这样避免了内存占用过大的情况。因为每一行的计算是互相独立的,所以可以利用openmp或MPI进行并行计算以提速。8核计算,这种方式可以达到28分钟的计算时间。
snowfall的解决方案:
snowfall的基本使用可以参考我。集群初始化与结束的语句基本一致,不同之处在于之前是做apply类型操作,现在是做矩阵相乘,关键是如下的语句:
sfClusterApplyLB和splitRows都是snow包的函数,由于snowfall依赖snow,所以只要载入snowfall包即可。参数CHUNK表示把矩阵按行分成几块,由splitRows函数完成分块,然后分发给不同的slave进行运算,这个分发的任务由sfClusterApplyLB函数完成,multiply_k函数是个自定义函数,形式如下,其完成的功能是对每一个分块的矩阵完成要实现的相乘、排序、取前10列的功能。{zh1}通过docall函数把各个分块得到的结果再组合到一起。
计算效率如下(balin, aragorn, dwalin都是机器名):
5 CPU balin单机23分钟?? 100分块,5核跑满
7 CPU (balin 3, aragorn 2, dwalin 2)15分钟?? 60分块,7核跑满
7 CPU (balin 3, aragorn 2, dwalin 2)15分钟?? 100分块,7核跑满
分块越少,需要被调配的任务越少,通常会运行得越快。但分块越少每个slave占内存就会越多,要解决这个矛盾,可以用多台机器,充分利用多机器的内存,分布计算。