Python多進(jìn)程庫multiprocessing中進(jìn)程池Pool類的使用詳解
問題起因
最近要將一個文本分割成好幾個topic,每個topic設(shè)計(jì)一個regressor,各regressor是相互獨(dú)立的,最后匯總所有topic的regressor得到總得預(yù)測結(jié)果。沒錯!類似bagging ensemble!只是我沒有抽樣。文本不大,大概3000行,topic個數(shù)為8,于是我寫了一個串行的程序,一個topic算完之后再算另一個topic??墒俏以诿總€topic中用了GridSearchCV來調(diào)參,又要選特征又要調(diào)整regressor的參數(shù),導(dǎo)致參數(shù)組合一共有1782種。我真是低估了調(diào)參的時間,程序跑了一天一夜最后因?yàn)橥沬mport一個庫導(dǎo)致最終的預(yù)測精度沒有算出來。后來想到,既然每個topic的預(yù)測都是獨(dú)立的,那是不是可以并行呢?
Python中的多線程與多進(jìn)程
但是聽聞Python的多線程實(shí)際上并不能真正利用多核,所以如果使用多線程實(shí)際上還是在一個核上做并發(fā)處理。不過,如果使用多進(jìn)程就可以真正利用多核,因?yàn)楦鬟M(jìn)程之間是相互獨(dú)立的,不共享資源,可以在不同的核上執(zhí)行不同的進(jìn)程,達(dá)到并行的效果。同時在我的問題中,各topic相互獨(dú)立,不涉及進(jìn)程間的通信,只需最后匯總結(jié)果,因此使用多進(jìn)程是個不錯的選擇。
multiprocessing
一個子進(jìn)程
multiprocessing模塊提供process類實(shí)現(xiàn)新建進(jìn)程。下述代碼是新建一個子進(jìn)程。
from multiprocessing import Process def f(name): print 'hello', name if __name__ == '__main__': p = Process(target=f, args=('bob',)) # 新建一個子進(jìn)程p,目標(biāo)函數(shù)是f,args是函數(shù)f的參數(shù)列表 p.start() # 開始執(zhí)行進(jìn)程 p.join() # 等待子進(jìn)程結(jié)束
上述代碼中p.join()的意思是等待子進(jìn)程結(jié)束后才執(zhí)行后續(xù)的操作,一般用于進(jìn)程間通信。例如有一個讀進(jìn)程pw和一個寫進(jìn)程pr,在調(diào)用pw之前需要先寫pr.join(),表示等待寫進(jìn)程結(jié)束之后才開始執(zhí)行讀進(jìn)程。
多個子進(jìn)程
如果要同時創(chuàng)建多個子進(jìn)程可以使用multiprocessing.Pool類。該類可以創(chuàng)建一個進(jìn)程池,然后在多個核上執(zhí)行這些進(jìn)程。
import multiprocessing import time def func(msg): print multiprocessing.current_process().name + '-' + msg if __name__ == "__main__": pool = multiprocessing.Pool(processes=4) # 創(chuàng)建4個進(jìn)程 for i in xrange(10): msg = "hello %d" %(i) pool.apply_async(func, (msg, )) pool.close() # 關(guān)閉進(jìn)程池,表示不能在往進(jìn)程池中添加進(jìn)程 pool.join() # 等待進(jìn)程池中的所有進(jìn)程執(zhí)行完畢,必須在close()之后調(diào)用 print "Sub-process(es) done."
輸出結(jié)果如下:
Sub-process(es) done. PoolWorker-34-hello 1 PoolWorker-33-hello 0 PoolWorker-35-hello 2 PoolWorker-36-hello 3 PoolWorker-34-hello 7 PoolWorker-33-hello 4 PoolWorker-35-hello 5 PoolWorker-36-hello 6 PoolWorker-33-hello 8 PoolWorker-36-hello 9
上述代碼中的pool.apply_async()是apply()函數(shù)的變體,apply_async()是apply()的并行版本,apply()是apply_async()的阻塞版本,使用apply()主進(jìn)程會被阻塞直到函數(shù)執(zhí)行結(jié)束,所以說是阻塞版本。apply()既是Pool的方法,也是Python內(nèi)置的函數(shù),兩者等價??梢钥吹捷敵鼋Y(jié)果并不是按照代碼for循環(huán)中的順序輸出的。
多個子進(jìn)程并返回值
apply_async()本身就可以返回被進(jìn)程調(diào)用的函數(shù)的返回值。上一個創(chuàng)建多個子進(jìn)程的代碼中,如果在函數(shù)func中返回一個值,那么pool.apply_async(func, (msg, ))的結(jié)果就是返回pool中所有進(jìn)程的值的對象(注意是對象,不是值本身)。
import multiprocessing import time def func(msg): return multiprocessing.current_process().name + '-' + msg if __name__ == "__main__": pool = multiprocessing.Pool(processes=4) # 創(chuàng)建4個進(jìn)程 results = [] for i in xrange(10): msg = "hello %d" %(i) results.append(pool.apply_async(func, (msg, ))) pool.close() # 關(guān)閉進(jìn)程池,表示不能再往進(jìn)程池中添加進(jìn)程,需要在join之前調(diào)用 pool.join() # 等待進(jìn)程池中的所有進(jìn)程執(zhí)行完畢 print ("Sub-process(es) done.") for res in results: print (res.get())
上述代碼輸出結(jié)果如下:
Sub-process(es) done. PoolWorker-37-hello 0 PoolWorker-38-hello 1 PoolWorker-39-hello 2 PoolWorker-40-hello 3 PoolWorker-37-hello 4 PoolWorker-38-hello 5 PoolWorker-39-hello 6 PoolWorker-37-hello 7 PoolWorker-40-hello 8 PoolWorker-38-hello 9
與之前的輸出不同,這次的輸出是有序的。
如果電腦是八核,建立8個進(jìn)程,在Ubuntu下輸入top命令再按下大鍵盤的1,可以看到每個CPU的使用率是比較平均的,如下圖:
在system monitor中也可以清楚看到執(zhí)行多進(jìn)程前后CPU使用率曲線的差異。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python中的json對象與string相互轉(zhuǎn)換教程
python里有json這個庫,但并沒有json這個類,所以所謂的json對象本質(zhì)上就是一個dict;而json這個庫,用于實(shí)現(xiàn)dict到string、string到dict的互轉(zhuǎn),這篇文章主要介紹了Python中的json對象與string相互轉(zhuǎn)換教程,需要的朋友可以參考下2022-11-11最好的Python DateTime 庫之 Pendulum 長篇解析
datetime 模塊是 Python 中最重要的內(nèi)置模塊之一,它為實(shí)際編程問題提供許多開箱即用的解決方案,非常靈活和強(qiáng)大。例如,timedelta 是我最喜歡的工具之一2021-11-11Python?生成多行重復(fù)數(shù)據(jù)的方法實(shí)現(xiàn)
本文主要介紹了Python?生成多行重復(fù)數(shù)據(jù)的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03Python實(shí)現(xiàn)異常值自動檢測的案例分享
在數(shù)據(jù)分析和機(jī)器學(xué)習(xí)中,異常值的檢測是一個關(guān)鍵步驟,它有助于識別數(shù)據(jù)中的異常模式和離群點(diǎn),本文將介紹Python中異常值檢測的實(shí)戰(zhàn)案例,使用一些常見的技術(shù)和庫,為大家提供全面的示例代碼和詳細(xì)解釋2024-01-01numpy.transpose對三維數(shù)組的轉(zhuǎn)置方法
下面小編就為大家分享一篇numpy.transpose對三維數(shù)組的轉(zhuǎn)置方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-04-04python opencv 二值化 計(jì)算白色像素點(diǎn)的實(shí)例
今天小編就為大家分享一篇python opencv 二值化 計(jì)算白色像素點(diǎn)的實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-07-07Python錯誤提示:[Errno 24] Too many open files的分析與解決
這篇文章主要給大家介紹了Python中出現(xiàn)錯誤提示:[Errno 24] Too many open files的分析與解決,需要的朋友可以參考借鑒,下面來一起看看吧。2017-02-02python3 動態(tài)模塊導(dǎo)入與全局變量使用實(shí)例
今天小編就為大家分享一篇python3 動態(tài)模塊導(dǎo)入與全局變量使用實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-12-12