基于官方文檔:
溫宿網(wǎng)站制作公司哪家好,找成都創(chuàng)新互聯(lián)公司!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、自適應(yīng)網(wǎng)站建設(shè)等網(wǎng)站項目制作,到程序開發(fā),運(yùn)營維護(hù)。成都創(chuàng)新互聯(lián)公司成立與2013年到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選成都創(chuàng)新互聯(lián)公司。
日樂購,剛才看到的一個博客,寫的都不太對,還是基于官方的比較穩(wěn)妥
我就是喜歡抄官方的,哈哈
通常我們使用Process實(shí)例化一個進(jìn)程,并調(diào)用 他的 start() 方法啟動它。
這種方法和 Thread 是一樣的。
上圖中,我寫了 p.join() 所以主進(jìn)程是 等待 子進(jìn)程執(zhí)行完后,才執(zhí)行 print("運(yùn)行結(jié)束")
否則就是反過來了(這個不一定,看你的語句了,順序其實(shí)是隨機(jī)的)例如:
主進(jìn)加個 sleep
所以不加join() ,其實(shí)子進(jìn)程和主進(jìn)程是各干各的,誰也不等誰。都執(zhí)行完后,文件運(yùn)行就結(jié)束了
上面我們用了 os.getpid() 和 os.getppid() 獲取 當(dāng)前進(jìn)程,和父進(jìn)程的id
下面就講一下,這兩個函數(shù)的用法:
os.getpid()
返回當(dāng)前進(jìn)程的id
os.getppid()
返回父進(jìn)程的id。 父進(jìn)程退出后,unix 返回初始化進(jìn)程(1)中的一個
windows返回相同的id (可能被其他進(jìn)程使用了)
這也就解釋了,為啥我上面 的程序運(yùn)行多次, 第一次打印的parentid 都是 14212 了。
而子進(jìn)程的父級 process id 是調(diào)用他的那個進(jìn)程的 id : 1940
視頻筆記:
多進(jìn)程:使用大致方法:
參考: 進(jìn)程通信(pipe和queue)
pool.map (函數(shù)可以有return 也可以共享內(nèi)存或queue) 結(jié)果直接是個列表
poll.apply_async() (同map,只不過是一個進(jìn)程,返回結(jié)果用 xx.get() 獲得)
報錯:
參考 :
把 pool = Pool() 放到 if name == " main ": 下面初始化搞定。
結(jié)果:
這個肯定有解釋的
測試多進(jìn)程計算效果:
進(jìn)程池運(yùn)行:
結(jié)果:
普通計算:
我們同樣傳入 1 2 10 三個參數(shù)測試:
其實(shí)對比下來開始快了一半的;
我們把循環(huán)里的數(shù)字去掉一個 0;
單進(jìn)程:
多進(jìn)程:
兩次測試 單進(jìn)程/進(jìn)程池 分別為 0.669 和 0.772 幾乎成正比的。
問題 二:
視圖:
post 視圖里面
Music 類:
直接報錯:
寫在 類里面也 在函數(shù)里用 self.pool 調(diào)用也不行,也是相同的錯誤。
最后 把 pool = Pool 直接寫在 search 函數(shù)里面,奇跡出現(xiàn)了:
前臺也能顯示搜索的音樂結(jié)果了
總結(jié)一點(diǎn),進(jìn)程這個東西,最好 寫在 直接運(yùn)行的函數(shù)里面,而不是 一個函數(shù)跳來跳去。因?yàn)樽詈罂赡?是在子進(jìn)程的子進(jìn)程運(yùn)行的,這是不許的,會報錯。
還有一點(diǎn),多進(jìn)程運(yùn)行的函數(shù)對象,不能是 lambda 函數(shù)。也許lambda 虛擬,在內(nèi)存??
使用 pool.map 子進(jìn)程 函數(shù)報錯,導(dǎo)致整個 pool 掛了:
參考:
主要你要,對函數(shù)內(nèi)部捕獲錯誤,而不能讓異常拋出就可以了。
關(guān)于map 傳多個函數(shù)參數(shù)
我一開始,就是正常思維,多個參數(shù),搞個元祖,讓參數(shù)一一對應(yīng)不就行了:
報錯:
參考:
普通的 process 當(dāng)讓可以穿多個參數(shù),map 卻不知道咋傳的。
apply_async 和map 一樣,不知道咋傳的。
最簡單的方法:
使用 starmap 而不是 map
結(jié)果:
子進(jìn)程結(jié)束
1.8399453163146973
成功拿到結(jié)果了
關(guān)于map 和 starmap 不同的地方看源碼:
關(guān)于apply_async() ,我沒找到多參數(shù)的方法,大不了用 一個迭代的 starmap 實(shí)現(xiàn)。哈哈
關(guān)于 上面源碼里面有 itertools.starmap
itertools 用法參考:
有個問題,多進(jìn)程最好不要使用全部的 cpu , 因?yàn)檫@樣可能影響其他任務(wù),所以 在進(jìn)程池 添加 process 參數(shù) 指定,cpu 個數(shù):
上面就是預(yù)留了 一個cpu 干其他事的
后面直接使用 Queue 遇到這個問題:
解決:
Manager().Queue() 代替 Queue()
因?yàn)?queue.get() 是堵塞型的,所以可以提前判斷是不是 空的,以免堵塞進(jìn)程。比如下面這樣:
使用 queue.empty() 空為True
任何一種編程語言,啟動進(jìn)程和關(guān)閉進(jìn)程都是跟操作系統(tǒng)相關(guān)的操作,python中與操作系統(tǒng)打交道的話,推薦使用os模塊。
os.system() 函數(shù)可以啟動一個進(jìn)程,執(zhí)行完之后返回狀態(tài)碼。
os.fork() 復(fù)制一個進(jìn)程,如果是子進(jìn)程返回0,如果是父進(jìn)程返回子進(jìn)程的pid,使用這個函數(shù)的時候,建議你學(xué)習(xí)一下linux編程的知識。
os.popen 以管道的方式創(chuàng)建進(jìn)程。
os.spawnl 也可以創(chuàng)建進(jìn)程,并能指定環(huán)境變量。
os.kill(pid, sig) 關(guān)閉一個進(jìn)程,pid是進(jìn)程號,sig是信號。與fork配合使用,例如你剛才用fork創(chuàng)建了一個子進(jìn)程,它的pid是11990, 那么調(diào)用
os.kill( 11990, signal.CTRL_BREAK_EVENT)
就以ctrl+c的方式殺死了這個進(jìn)程。
另外還有一個模塊multiprocessing,這個模塊封裝了很多創(chuàng)建進(jìn)程和進(jìn)程間通信的操作,可以讓你發(fā)揮多核的威力。
如果想了解進(jìn)程 可以先看一下這一篇 python中的進(jìn)程-理論部分
python中的多線程無法利用多核優(yōu)勢,如果想要充分地使用多核CPU的資源(os.cpu_count()查看),在python中大部分情況需要使用多進(jìn)程。Python提供了multiprocessing。
multiprocessing模塊用來開啟子進(jìn)程,并在子進(jìn)程中執(zhí)行我們定制的任務(wù)(比如函數(shù)),該模塊與多線程模塊threading的編程接口類似。
multiprocessing模塊的功能眾多:支持子進(jìn)程、通信和共享數(shù)據(jù)、執(zhí)行不同形式的同步,提供了Process、Queue、Pipe、Lock等組件。
需要再次強(qiáng)調(diào)的一點(diǎn)是:與線程不同,進(jìn)程沒有任何共享狀態(tài),進(jìn)程修改的數(shù)據(jù),改動僅限于該進(jìn)程內(nèi)。
創(chuàng)建進(jìn)程的類 :
參數(shù)介紹:
group參數(shù)未使用,值始終為None
target表示調(diào)用對象,即子進(jìn)程要執(zhí)行的任務(wù)
args表示調(diào)用對象的位置參數(shù)元組,args=(1,2,'tiga',)
kwargs表示調(diào)用對象的字典,kwargs={'name':'tiga','age':18}
name為子進(jìn)程的名稱
方法介紹:
p.start():啟動進(jìn)程,并調(diào)用該子進(jìn)程中的p.run()
p.run():進(jìn)程啟動時運(yùn)行的方法,正是它去調(diào)用target指定的函數(shù),我們自定義類的類中一定要實(shí)現(xiàn)該方法
p.terminate():強(qiáng)制終止進(jìn)程p,不會進(jìn)行任何清理操作,如果p創(chuàng)建了子進(jìn)程,該子進(jìn)程就成了僵尸進(jìn)程,使用該方法需要特別小心這種情況。如果p還保存了一個鎖那么也將不會被釋放,進(jìn)而導(dǎo)致死鎖
p.is_alive():如果p仍然運(yùn)行,返回True
p.join([timeout]):主線程等待p終止(強(qiáng)調(diào):是主線程處于等的狀態(tài),而p是處于運(yùn)行的狀態(tài))。timeout是可選的超時時間,需要強(qiáng)調(diào)的是,p.join只能join住start開啟的進(jìn)程,而不能join住run開啟的進(jìn)程
屬性介紹:
注意:在windows中Process()必須放到# if __name__ == '__main__':下
創(chuàng)建并開啟子進(jìn)程的兩種方式
方法一:
方法二:
有了join,程序不就是串行了嗎???
terminate與is_alive
name與pid