python進程池來運行多進程

1. 任務需求

很多情況下我們處理數據時,因爲數據比較多,所以需要浪費很多時間,而如果我們用的是服務器的話,那麼cpu的線程數一般比較高,所以我們可以開啓多個線程同時工作,可以加快我們的處理速度。

2. 簡單例子

現在我們來看一個簡單例子,看看怎麼使用python的進程池。
首先就是導入進程池的包:

from multiprocessing import Pool

然後我們需要將我們需要處理的事情封裝成一個函數,這裏處理一個簡單的任務:

def multi_pool_test(i):
    return (i+1)*10

然後就可以直接程序化:

pool = Pool(processes=3) # processes爲開啓的線程數
results = []
for i in range(100):
    print (i)
    result = pool.apply_async(multi_pool_test,(i,))
    results.append(result)
pool.close()
pool.join()
results = [result.get() for result in results] #.get讀取結果
print (results)

3 複雜例子

現在我們要處理一個數據,數據格式如下:
在這裏插入圖片描述
我們只讀取前面的標籤和後面的文字,然後後面的問題用nltk處理:
先看看不用進程池的方法:

    def read_file(self,path):
        '''
        read file through open, i don't know how to use pandas
        :param path: file path
        :return:
        '''
        datas = open(path,"r",encoding="utf-8").read().splitlines()
        labels = []
        texts = []
        for i,data in enumerate(datas):
            data = data.lower()
            if i%10000==0:
                print (i,len(datas))
            data = data.split(',"',1)
            labels.append(int(data[0].strip("\""))-1)
            texts.append(nltk.word_tokenize(data[1])[0:hp.max_word_length])
        return texts,labels

然後我們處理的數據集有300萬行,速度太慢,我們就將使用進程池進行處理:

    def multi_process(self,datas):
        labels = []
        texts = []
        for i,data in enumerate(datas):
            data = data.lower()
            if i%10000==0:
                print (i,len(datas))
            data = data.split(',"',1)
            labels.append(int(data[0].strip("\""))-1)
            texts.append(nltk.word_tokenize(data[1])[0:hp.max_word_length])
        return [texts,labels]
    def multi_read_file(self,path):
        labels = []
        texts = []
        results = []
        multi_process = 20
        pool = Pool(processes=multi_process)
        datas = open(path, "r", encoding="utf-8").read().splitlines()
        n = int(len(datas)/multi_process)
        for i in range(multi_process):
            result = pool.apply_async(self.multi_process,(datas[i*n:(i+1)*n],))
            results.append(result)
        pool.close()
        pool.join()
        for result in results:
            result = result.get()
            texts.extend(result[0])
            labels.extend(result[1])
        return texts,labels

然後速度就快了20倍左右。

4. 一個問題

以前我寫進程池的時候,發現一切都寫對了,但是每次最多開啓兩個進程,最終發現是邏輯錯誤,這裏進程創建分爲兩部分:
第一步就是創建進程然後拷入所需的數據,第二步是進行數據處理。如果我們的數據太大,那麼創建進程和數據處理的步驟就會很慢,而如果數據處理太快,因爲創建進程和拷貝數據是主進程做的事情,而主進程只有一個,所以這一步是串行的。如果需要拷貝數據太大而處理非常快,就會出現只有兩個進程,而且只有一個真正工作的情況,此時的進程池會比單進程還慢。
解決辦法很簡單,就像我上面寫的一樣,就是將數據分爲很多份,每個進程處理一份數據,而不是一個數據,這樣雖然數據讀入依舊很慢,但是數據處理也很慢,就會開啓很多進程的。
願大家數據處理能夠又快又好。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章