用Python多进程做数据预处理能大幅提高效率

在做机器学习之前,有一项工作是非常耗时耗力的,那就是数据预处理。有时候数据预处理花的时间比训练的时间还要多。有很多办法可以提高数据预处理的效率,我在利用python的 multiprocessing写多进程代码的时候,发现对数据预处理处理能起到很好的效果。

首先说说我的机器,之前是i5 4590 +8G内存+机械硬盘,一个程序处理起来总共要花30多个小时,当时只用到一个核,哪怕我把数据切开,同时跑4个程序分别处理4部分数据,后面几个核也无法用满。我程序上做了大量优化,最后处理一下是26个小时。这是根本无法接受的。
5.1的时候我换了机器,i5 9600k+32G内存+机械硬盘。这个程序处理时间缩短到了11个小时。但是CPU的6个核根本跑不满,完全没有利用到其他5个核。下面这个截图就是某个瞬间,CPU各个核的占用情况。

用Python多进程做数据预处理能大幅提高效率_第1张图片

之后学了一些东西,了解了并行处理,改写了程序,
原来,我一直以为的多开程序,并不是并行处理,无法利用到多个核,而是每一个程序共享cpu某一个核的一段处理时间。除非程序实在消耗太大,才会依次开始利用到后面的核。
所以最重要的还是单核的频率,频率越高,性能越强,多个程序切换起来越快。


再看看我改写的程序,这次一个主进程带上了6个子进程(每一个进程都是一个程序,只不过这种情况下他们有些关系,比如谷歌浏览器在任务管理器里面会有发现一堆chrome.exe。这种情况下,就真正利用到了多核了。每一个核都100%满占用。
用Python多进程做数据预处理能大幅提高效率_第2张图片

 

此时温度大约50%。

用Python多进程做数据预处理能大幅提高效率_第3张图片

这样截图的进程树其实有12个,但是一个屏幕截不下,我一开始用的是6个子进程,想试试说12个行不行,结果还真行。i5 9600k的运算能力比我想的强多了。

用Python多进程做数据预处理能大幅提高效率_第4张图片

最后数据处理时间缩短到了1小时14分。总共处理了98万个数据点。

 

所以简单总结一下
1. 没有关系的各个程序(进程)分别获取CPU的一段处理时间,CPU在这段时间里面运行程序的一些指令,遇到IO的时候,就会切换到下一个程序。
2. 如果一个核就能完成当前程序的运算,那么就不会麻烦第二个核。
3. 所以简单的说多开并不能利用到多核。
4. 如果一个程序做了多核的优化(就像我上面做的那样),那么就会同时利用到多个核进行计算。
5. 如果多开的程序中有这样的程序,那么在某个计算时段多个核就会被利用起来。(一个程序也不是时刻都需要多核计算的)
6. 相对来说,还是主频更为重要,因为运算会快,这样多开程序切换也快。如果每个程序被分配了固定的指令数,处理完就切换下一个程序的话,主频高的程序就能够更快的完成这些指令。
7. 当你明确有多核的任务时,多核的威力就会发挥出来!

 

代码非常简单,基本上看一下multiprocessing 照抄就行了。总共也没几行代码。

稍微解释一下,num_process==1的时候,一般用来处理少量数据,或者用来debug。Array用来记录每个进程处理了多少数据,最后汇总起来。MPModelManager继承了process,实现了run。这个在multiprocessing的文档里面都有。

from multiprocessing import Lock, Array
from manager import MPModelManager

if num_process == 1:
        t0 = datetime.now()
        arr = Array('i',num_process)
        lock = Lock()
        spid = 0
        mpsm = MPSampleManager(model_param,lock,arr, spid )
        mpsm.run()
        t1 = datetime.now()
        print("处理%s用时:%s" % (model_param['modelcode'],(t1 - t0)))

else:
      
        
        arr = Array('i',num_process)
        print( arr[:])
        lock = Lock()
        li_child_proc = []
        spid = 0

        t0 = datetime.now()
        while spid < num_process:
            mpsm = MPSampleManager(model_param,lock,arr,spid )
            li_child_proc.append(mpsm)
            mpsm.start()
            spid+=1

        while True:
            if not 0 in arr:
                break
            print(arr[:])
            sleep(30)

        for sm in li_child_proc:
            sm.join()
        
        print(arr[:])
        num_samples = sum(arr)
        print("totally find %d samples...start to merge" % num_samples)
        

        t1 = datetime.now()
        

 

你可能感兴趣的:(机器学习)