問題描述
當(dāng)我們有一個(gè)很長(zhǎng)很長(zhǎng)的任務(wù)隊(duì)列(mission_list)和閾值對(duì)應(yīng)的一個(gè)處理函數(shù)(missionFunction)時(shí),我們一般采用如下的方式進(jìn)行處理:
mission_list=[1,2,3,4,5]
def missionFunction(x):
return x**2
#一般情況下的處理方法
for x in mission_list:
XXX=missionFunction(x)
但是亩冬,如果這任務(wù)列表很長(zhǎng)很長(zhǎng)词顾,處理函數(shù)很復(fù)雜(占用cpu)時(shí)映琳,單核往往需要很長(zhǎng)的時(shí)間進(jìn)行處理牙咏,此時(shí)早直,Multiprocess便可以極大的提高我們程序的運(yùn)行速度祷肯,相關(guān)內(nèi)容請(qǐng)借鑒multiprocessing --- 基于進(jìn)程的并行 — Python 3.10.4 文檔唯卖。
以上這種場(chǎng)景下粱玲,推薦大家采用最簡(jiǎn)單的進(jìn)程池+map的方法進(jìn)行處理,標(biāo)準(zhǔn)的寫法拜轨,chunksize要借鑒官方的說法抽减,最好大一點(diǎn):
from multiprocessing import Pool
mission_list=[1,2,3,4,5]
def missionFunction(x):
return x**2
#一般情況下的多進(jìn)程寫法
with Pool(processes=n) as pool:
pool.map(missionFunction, mission_list,chunksize=1000)
...
內(nèi)存優(yōu)化
但是!i夏搿B殉痢!如果我們的任務(wù)列表非常的長(zhǎng)法牲,這會(huì)導(dǎo)致多進(jìn)程還沒跑起來之前史汗,內(nèi)存已經(jīng)撐爆了,任務(wù)自然沒法完成拒垃,此時(shí)我們有幾種辦法進(jìn)行優(yōu)化:
1. 進(jìn)程的啟動(dòng)方式
進(jìn)程的啟動(dòng)方法有三種停撞,可參考官方文檔:
[圖片上傳失敗...(image-48cd3c-1650511153989)]
在linux環(huán)境下,使用forkserver可以節(jié)省很多的內(nèi)存空間悼瓮,因?yàn)檫M(jìn)程啟動(dòng)的是一個(gè)服務(wù)戈毒,不會(huì)把主進(jìn)程的數(shù)據(jù)全部復(fù)制
2. 采用imap
采用imap會(huì)極大的節(jié)省空間,它返回的是一個(gè)迭代器横堡,也就是結(jié)果列表:
with Pool() as pool:
ans= pool.imap(missionFunction, mission_list)
for ret in ans:
# do something
但注意埋市,以上寫法中,你寫的結(jié)果迭代部分必須寫在with下面命贴〉勒或者采用另一種寫法:
pool = Pool()
ans= pool.imap(missionFunction, mission_list)
...
for ret in ans:
# do something
pool.close()
3. mission_list的優(yōu)化
還有最后一種,當(dāng)你的missionlist實(shí)在太大了胸蛛,導(dǎo)致你在生成missionlist的時(shí)候已經(jīng)把內(nèi)存撐爆了污茵,這個(gè)時(shí)候就得優(yōu)化mission_list了,如果你的mission_list是通過一個(gè)for循環(huán)生成的葬项,你可以使用yield字段泞当,將其封裝為一個(gè)迭代器,傳入進(jìn)程池:
## 你的原始寫法可能是這樣的
def generate_mission_list(**args):
mission_list=[]
#這里有很多相關(guān)的代碼玷室,用于生成mission_list
for ... in ...:
...
mission_list.append(mission)
return mission_list
## 執(zhí)行
mission_list=generate_mission_list(...)
for mission in mission_list:
.....
## 建議的寫法
def generate_mission_list(**args):
#這里有很多相關(guān)的代碼零蓉,用于生成mission_list
for ... in ...:
...
yield mission
mission_list=generate_mission_list(...)
for mission in mission_list:
.....
這樣子笤受,我們就封裝好了mission_list穷缤,它是一個(gè)可迭代對(duì)象,在取數(shù)據(jù)的時(shí)候才會(huì)將數(shù)據(jù)拉到內(nèi)存
我在項(xiàng)目中結(jié)合了后兩種方法箩兽,原本256G的內(nèi)存都不夠用津肛,但在修改后內(nèi)存只占用了不到10G。希望能夠幫助到你