程序性能杂记

最近在写一个迭代产生句子vector的程序,会为每个sentence和word产生对应的vector。因此,需要更新的全局数据是比较大的。

由于对于sentence 的 vector 只在处理到对应的句子的时候才会更新,因此需要更多的迭代来拟合,因此,初步觉得迭代的次数会比较多。

实验的机器有16个虚拟线程,无GPU,因此我从刚开始就考虑到采用多核并行。


刚开始使用python写了一个单进程的程序验证了一下算法。 之后,有了两个选择,一个是用python的多进程加速,也就是multiprocessing这个库;另外一个选择是用C++实现,并行方面,pthread或者MPI等很多选择。 

首先是不太成功的multiprocessing(问题在后面找到了),出现的困难如下:

1、共享数据:

multiprocessing库基础上的共享数据,有自带的Array, Value等共享数据类型是比较好的选择。 

当然,如果数据量比较大,单进程内是用numpy.array 。 从numpy.array 转成各进程共享的 Array等数据格式的方法如下:

ori_vecs = vecs.reshape( n_rows * n_cols )
shared_array = multiprocessing.Array('d', ori_vecs)

这里第一行是将多维的numpy.array 转化为 一维,之后直接转化。不同库中的两种数据类型直接转化,可以认为具体数据的存储方式是相同的。

之后,在单个线程内,如果要将multiprocessing.Array转化为numpy.array,可以用如下代码:

vecs = numpy.frombuffer(shared_array.get_obj())

当然,原有的维度的信息肯定是丢失了,可以写一个封装的类来实现二维向量:

class Arr(object):
    def __init__(self, arr, len_vec):
        self.arr = arr
        self.len_vec = len_vec

    def __getitem__(self, index, *args):
        if isinstance(index, tuple):
            index = index[0]
        start = index * self.len_vec
        end = start + self.len_vec 
        return self.arr[start : end ]


2、性能差

在并行模型方面,我是在更新每个元素的vector 时会对全局数据加锁,这个带来了很大的性能问题。

体现在python版本上,就是用十个进程依旧只有200% 的CPU占用,200%这个数据比较精确。 在网上查,有说是进程之间通信,导致整体CPU占用过低。

当然,这个是加锁的问题导致的。


python版本的性能问题一直无解,所以我又实现了C++的版本,当然,单进程下,C++跑的更快。

手上有4台服务器,所以最初看了MPI。 类似pLDA,如果训练的句子数据拆分到4台机器上,那相应的 sentence vector 也可以拆分,通过MPI就行本地更新便可。 

最终用pthread实现,是由于我并没有那么大的数据需要发布去处理,单机跑,pthread应该要简单而且快速。

直接照搬python代码里面的,只是向量运算需要自己写了一些工具类。 写完之后,多进程下CPU的占用依旧少的可怜。

用gprof 作性能分析,之后用了 gprof2dot 结合 sfdp 画了一张巨大的结构图,显示问题出在 updateVec 这个函数上,Vec是封装了C++ STL 中的 vector,加了一些向量运算的方法,更新和norm都是在加锁的情况进行的。 算法会同时更新 word vector 和 sentence vector ,对全局数据加锁,这就导致及时只是更新其中一个vector,也会堵塞所有尝试更新其他 vector 的进程, 而我的 sentence vector 有600k,呵呵...

狠狠心,把锁都去掉了,把vector 的更新从整体变为基于单个item的更新,(更新操作是一个累加梯度的过程),在10进程下,CPU终于上800%了。

把之前的python代码也类似改了一下,果然CPU占用上去了。 


总结:

1、全局数据,如果更新操作非常稀疏,更新操作是一个累加累减的过程,那加锁的意义有限,而且非常影响并行的性能。

2、Python的并行程序。 由于python的设计天生就不适合多核并行,尽管有众多的库的支持,但是往往文档各方面并不成熟,如果应用稍微复杂一点,就扑街了。 纯计算的还是选择C或者C++,用的模型都比较成熟,而且文档众多,开发风险小很多。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值