multiprocessing 是一個(gè)支持使用與 threading 模塊類似的 API 來(lái)產(chǎn)生進(jìn)程的包。 multiprocessing 包同時(shí)提供了本地和遠(yuǎn)程并發(fā)操作,通過(guò)使用子進(jìn)程而非線程有效地繞過(guò)了 全局解釋器鎖。 因此,multiprocessing 模塊允許程序員充分利用給定機(jī)器上的多個(gè)處理器。 它在 Unix 和 Windows 上均可運(yùn)行。
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:空間域名、網(wǎng)頁(yè)空間、營(yíng)銷軟件、網(wǎng)站建設(shè)、古丈網(wǎng)站維護(hù)、網(wǎng)站推廣。
1、multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
2、相關(guān)方法
輸出結(jié)果如下:
Pool提供了一種快捷的方法,賦予函數(shù)并行化處理一系列輸入值的能力,可以將輸入數(shù)據(jù)分配給不同進(jìn)程處理(數(shù)據(jù)并行)。下面的例子演示了在模塊中定義此類函數(shù)的常見(jiàn)做法,以便子進(jìn)程可以成功導(dǎo)入該模塊。這個(gè)數(shù)據(jù)并行的基本例子使用了 Pool 。
將在標(biāo)準(zhǔn)輸出中打印
其中:
(1)p.apply(func [, args [, kwargs]]):在一個(gè)池工作進(jìn)程中執(zhí)行func( args, kwargs),然后返回結(jié)果。需要強(qiáng)調(diào)的是:此操作并不會(huì)在所有池工作進(jìn)程中并執(zhí)行func函數(shù)。如果要通過(guò)不同參數(shù)并發(fā)地執(zhí)行func函數(shù),必須從不同線程調(diào)用p.apply()函數(shù)或者使用p.apply_async()
(2)p.apply_async(func [, args [, kwargs]]):在一個(gè)池工作進(jìn)程中執(zhí)行func( args,**kwargs),然后返回結(jié)果。此方法的結(jié)果是 AsyncResult類的實(shí)例,callback是可調(diào)用對(duì)象,接收輸入?yún)?shù)。當(dāng)func的結(jié)果變?yōu)榭捎脮r(shí),將理解傳遞給callback。callback禁止執(zhí)行任何阻塞操作,否則將接收其他異步操作中的結(jié)果。多進(jìn)程并發(fā)!
(3)p.close():關(guān)閉進(jìn)程池,防止進(jìn)一步操作。如果所有操作持續(xù)掛起,它們將在工作進(jìn)程終止前完成
(4)p.jion():等待所有工作進(jìn)程退出。此方法只能在close()或teminate()之后調(diào)用
1.?Process
創(chuàng)建進(jìn)程的類:Process([group?[,?target?[,?name?[,?args?[,?kwargs]]]]]),target表示調(diào)用對(duì)象,args表示調(diào)用對(duì)象的位置參數(shù)元組。kwargs表示調(diào)用對(duì)象的字典。name為別名。group實(shí)質(zhì)上不使用。
方法:is_alive()、join([timeout])、run()、start()、terminate()。其中,Process以start()啟動(dòng)某個(gè)進(jìn)程。
屬性:authkey、daemon(要通過(guò)start()設(shè)置)、exitcode(進(jìn)程在運(yùn)行時(shí)為None、如果為–N,表示被信號(hào)N結(jié)束)、name、pid。其中daemon是父進(jìn)程終止后自動(dòng)終止,且自己不能產(chǎn)生新進(jìn)程,必須在start()之前設(shè)置。
例1.1:創(chuàng)建函數(shù)并將其作為單個(gè)進(jìn)程
import?multiprocessing
import?time
def?worker(interval):
n?=?5
while?n??0:
print("The?time?is?{0}".format(time.ctime()))
time.sleep(interval)
n?-=?1
if?__name__?==?"__main__":
p?=?multiprocessing.Process(target?=?worker,?args?=?(3,))
p.start()
print?"p.pid:",?p.pid
print?"p.name:",?p.name
print?"p.is_alive:",?p.is_alive()
結(jié)果
12345678????p.pid:?8736p.name:?Process-1p.is_alive:?TrueThe?time?is?Tue?Apr?21?20:55:12?2015The?time?is?Tue?Apr?21?20:55:15?2015The?time?is?Tue?Apr?21?20:55:18?2015The?time?is?Tue?Apr?21?20:55:21?2015The?time?is?Tue?Apr?21?20:55:24?2015????
例1.2:創(chuàng)建函數(shù)并將其作為多個(gè)進(jìn)程
import?multiprocessing
import?time
def?worker_1(interval):
print?"worker_1"
time.sleep(interval)
print?"end?worker_1"
def?worker_2(interval):
print?"worker_2"
time.sleep(interval)
print?"end?worker_2"
def?worker_3(interval):
print?"worker_3"
time.sleep(interval)
print?"end?worker_3"
if?__name__?==?"__main__":
p1?=?multiprocessing.Process(target?=?worker_1,?args?=?(2,))
p2?=?multiprocessing.Process(target?=?worker_2,?args?=?(3,))
p3?=?multiprocessing.Process(target?=?worker_3,?args?=?(4,))
p1.start()
p2.start()
p3.start()
print("The?number?of?CPU?is:"?+?str(multiprocessing.cpu_count()))
for?p?in?multiprocessing.active_children():
print("child???p.name:"?+?p.name?+?"\tp.id"?+?str(p.pid))
print?"END!!!!!!!!!!!!!!!!!"
結(jié)果
1234567891011????The?number?of?CPU?is:4child???p.name:Process-3????p.id7992child???p.name:Process-2????p.id4204child???p.name:Process-1????p.id6380END!!!!!!!!!!!!!!!!!worker_1worker_3worker_2end?worker_1end?worker_2end?worker_3????
例1.3:將進(jìn)程定義為類
import?multiprocessing
import?time
class?ClockProcess(multiprocessing.Process):
def?__init__(self,?interval):
multiprocessing.Process.__init__(self)
self.interval?=?interval
def?run(self):
n?=?5
while?n??0:
print("the?time?is?{0}".format(time.ctime()))
time.sleep(self.interval)
n?-=?1
if?__name__?==?'__main__':
p?=?ClockProcess(3)
p.start()??????
注:進(jìn)程p調(diào)用start()時(shí),自動(dòng)調(diào)用run()
結(jié)果
12345????the?time?is?Tue?Apr?21?20:31:30?2015the?time?is?Tue?Apr?21?20:31:33?2015the?time?is?Tue?Apr?21?20:31:36?2015the?time?is?Tue?Apr?21?20:31:39?2015the?time?is?Tue?Apr?21?20:31:42?2015
基于官方文檔:
日樂(lè)購(gòu),剛才看到的一個(gè)博客,寫的都不太對(duì),還是基于官方的比較穩(wěn)妥
我就是喜歡抄官方的,哈哈
通常我們使用Process實(shí)例化一個(gè)進(jìn)程,并調(diào)用 他的 start() 方法啟動(dòng)它。
這種方法和 Thread 是一樣的。
上圖中,我寫了 p.join() 所以主進(jìn)程是 等待 子進(jìn)程執(zhí)行完后,才執(zhí)行 print("運(yùn)行結(jié)束")
否則就是反過(guò)來(lái)了(這個(gè)不一定,看你的語(yǔ)句了,順序其實(shí)是隨機(jī)的)例如:
主進(jìn)加個(gè) sleep
所以不加join() ,其實(shí)子進(jìn)程和主進(jìn)程是各干各的,誰(shuí)也不等誰(shuí)。都執(zhí)行完后,文件運(yùn)行就結(jié)束了
上面我們用了 os.getpid() 和 os.getppid() 獲取 當(dāng)前進(jìn)程,和父進(jìn)程的id
下面就講一下,這兩個(gè)函數(shù)的用法:
os.getpid()
返回當(dāng)前進(jìn)程的id
os.getppid()
返回父進(jìn)程的id。 父進(jìn)程退出后,unix 返回初始化進(jìn)程(1)中的一個(gè)
windows返回相同的id (可能被其他進(jìn)程使用了)
這也就解釋了,為啥我上面 的程序運(yùn)行多次, 第一次打印的parentid 都是 14212 了。
而子進(jìn)程的父級(jí) process id 是調(diào)用他的那個(gè)進(jìn)程的 id : 1940
視頻筆記:
多進(jìn)程:使用大致方法:
參考: 進(jìn)程通信(pipe和queue)
pool.map (函數(shù)可以有return 也可以共享內(nèi)存或queue) 結(jié)果直接是個(gè)列表
poll.apply_async() (同map,只不過(guò)是一個(gè)進(jìn)程,返回結(jié)果用 xx.get() 獲得)
報(bào)錯(cuò):
參考 :
把 pool = Pool() 放到 if name == " main ": 下面初始化搞定。
結(jié)果:
這個(gè)肯定有解釋的
測(cè)試多進(jìn)程計(jì)算效果:
進(jìn)程池運(yùn)行:
結(jié)果:
普通計(jì)算:
我們同樣傳入 1 2 10 三個(gè)參數(shù)測(cè)試:
其實(shí)對(duì)比下來(lái)開始快了一半的;
我們把循環(huán)里的數(shù)字去掉一個(gè) 0;
單進(jìn)程:
多進(jìn)程:
兩次測(cè)試 單進(jìn)程/進(jìn)程池 分別為 0.669 和 0.772 幾乎成正比的。
問(wèn)題 二:
視圖:
post 視圖里面
Music 類:
直接報(bào)錯(cuò):
寫在 類里面也 在函數(shù)里用 self.pool 調(diào)用也不行,也是相同的錯(cuò)誤。
最后 把 pool = Pool 直接寫在 search 函數(shù)里面,奇跡出現(xiàn)了:
前臺(tái)也能顯示搜索的音樂(lè)結(jié)果了
總結(jié)一點(diǎn),進(jìn)程這個(gè)東西,最好 寫在 直接運(yùn)行的函數(shù)里面,而不是 一個(gè)函數(shù)跳來(lái)跳去。因?yàn)樽詈罂赡?是在子進(jìn)程的子進(jìn)程運(yùn)行的,這是不許的,會(huì)報(bào)錯(cuò)。
還有一點(diǎn),多進(jìn)程運(yùn)行的函數(shù)對(duì)象,不能是 lambda 函數(shù)。也許lambda 虛擬,在內(nèi)存??
使用 pool.map 子進(jìn)程 函數(shù)報(bào)錯(cuò),導(dǎo)致整個(gè) pool 掛了:
參考:
主要你要,對(duì)函數(shù)內(nèi)部捕獲錯(cuò)誤,而不能讓異常拋出就可以了。
關(guān)于map 傳多個(gè)函數(shù)參數(shù)
我一開始,就是正常思維,多個(gè)參數(shù),搞個(gè)元祖,讓參數(shù)一一對(duì)應(yīng)不就行了:
報(bào)錯(cuò):
參考:
普通的 process 當(dāng)讓可以穿多個(gè)參數(shù),map 卻不知道咋傳的。
apply_async 和map 一樣,不知道咋傳的。
最簡(jiǎn)單的方法:
使用 starmap 而不是 map
結(jié)果:
子進(jìn)程結(jié)束
1.8399453163146973
成功拿到結(jié)果了
關(guān)于map 和 starmap 不同的地方看源碼:
關(guān)于apply_async() ,我沒(méi)找到多參數(shù)的方法,大不了用 一個(gè)迭代的 starmap 實(shí)現(xiàn)。哈哈
關(guān)于 上面源碼里面有 itertools.starmap
itertools 用法參考:
有個(gè)問(wèn)題,多進(jìn)程最好不要使用全部的 cpu , 因?yàn)檫@樣可能影響其他任務(wù),所以 在進(jìn)程池 添加 process 參數(shù) 指定,cpu 個(gè)數(shù):
上面就是預(yù)留了 一個(gè)cpu 干其他事的
后面直接使用 Queue 遇到這個(gè)問(wèn)題:
解決:
Manager().Queue() 代替 Queue()
因?yàn)?queue.get() 是堵塞型的,所以可以提前判斷是不是 空的,以免堵塞進(jìn)程。比如下面這樣:
使用 queue.empty() 空為True