詳解python之多進(jìn)程和進(jìn)程池(Processing庫)
環(huán)境:win7+python2.7
一直想學(xué)習(xí)多進(jìn)程或多線程,但之前只是單純看一點(diǎn)基礎(chǔ)知識還有簡單的介紹,無法理解怎么去應(yīng)用,直到前段時間看了github的一個爬蟲項(xiàng)目涉及到多進(jìn)程,多線程相關(guān)內(nèi)容,一邊看一邊百度相關(guān)知識點(diǎn),現(xiàn)在把一些相關(guān)知識點(diǎn)和一些應(yīng)用寫下來做個記錄.
首先說下什么是進(jìn)程:進(jìn)程是程序在計(jì)算機(jī)上的一次執(zhí)行活動,當(dāng)運(yùn)行一個程序的時候,就啟動了一個進(jìn)程.而進(jìn)程又分為系統(tǒng)進(jìn)程和用戶進(jìn)程.只要是用于完成操作系統(tǒng)的各種功能的進(jìn)程就是系統(tǒng)進(jìn)程,它們就是處于運(yùn)行狀態(tài)下的操作系統(tǒng)本身;而所有由你啟動的進(jìn)程都是用戶進(jìn)程。進(jìn)程是操作系統(tǒng)進(jìn)行資源分配的單位。
直觀點(diǎn)說,在任務(wù)管理器的用戶名上標(biāo)明system的是系統(tǒng)進(jìn)程,標(biāo)明administrator的是用戶進(jìn)程,另外net是網(wǎng)洛,lcacal service是本地服務(wù),關(guān)于進(jìn)程更加具體的信息可以百科,這里得省點(diǎn)力氣,不然收不回了.
一.多進(jìn)程的簡單使用
如圖,multiprocessing有多個函數(shù),很多我也還沒去了解,這里只講我目前了解的.
進(jìn)程創(chuàng)建:Process(target=主要運(yùn)行的函數(shù),name=自定義進(jìn)程名稱可不寫,args=(參數(shù)))
方法:
- is_alive():判斷進(jìn)程是否存活
- join([timeout]):子進(jìn)程結(jié)束再執(zhí)行下一步,timeout為超時時間,有時進(jìn)程遇到阻塞,為了程序能夠運(yùn)行下去而設(shè)置超時時間
- run():如果在創(chuàng)建Process對象的時候不指定target,那么就會默認(rèn)執(zhí)行Process的run方法
- start():啟動進(jìn)程,區(qū)分run()
- terminate():終止進(jìn)程,關(guān)于終止進(jìn)程沒有這么簡單,貌似用psutil包會更好,有機(jī)會以后了解更多再寫下。
其中,Process以start()啟動某個進(jìn)程。
屬性:
- authkey: 在文檔中authkey()函數(shù)找到這么一句話:Set authorization key of process設(shè)置過程的授權(quán)密鑰 ,目前沒找到相關(guān)應(yīng)用實(shí)例,這個密鑰是怎么用的呢?文章不提
- daemon:父進(jìn)程終止后自動終止,且自己不能產(chǎn)生新進(jìn)程,必須在start()之前設(shè)置
- exitcode:進(jìn)程在運(yùn)行時為None、如果為–N,表示被信號N結(jié)束
- name:進(jìn)程的名字,自定義
- pid:每個進(jìn)程有唯一的PID編號。
1.Process(),start(),join()
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if __name__ == '__main__': a=time.time() p1=Process(target=fun1,args=(4,)) p2 = Process(target=fun2, args=(6,)) p1.start() p2.start() p1.join() p2.join() b=time.time() print 'finish',b-a
這里一共開了兩個進(jìn)程,p1和p2,arg=(4,)中的4是fun1函數(shù)的參數(shù),這里要用tulpe類型,如果兩個參數(shù)或更多就是arg=(參數(shù)1,參數(shù)2...),之后用start()啟動進(jìn)程,我們設(shè)置等待p1和p2進(jìn)程結(jié)束再執(zhí)行下一步.來看下面的運(yùn)行結(jié)果,fun2和fun1基本在同一時間開始運(yùn)行,當(dāng)運(yùn)行完畢(fun1睡眠4秒,同時fun2睡眠6秒),才執(zhí)行print 'finish',b-a語句
this is fun2 Mon Jun 05 13:48:04 2017 this is fun1 Mon Jun 05 13:48:04 2017 fun1 finish Mon Jun 05 13:48:08 2017 fun2 finish Mon Jun 05 13:48:10 2017 finish 6.20300006866 Process finished with exit code 0
我們再來看下start()與join()處于不同位置會發(fā)生什么
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if __name__ == '__main__': a=time.time() p1=Process(target=fun1,args=(4,)) p2 = Process(target=fun2, args=(6,)) p1.start() p1.join() p2.start() p2.join() b=time.time() print 'finish',b-a
結(jié)果:
this is fun1 Mon Jun 05 14:19:28 2017 fun1 finish Mon Jun 05 14:19:32 2017 this is fun2 Mon Jun 05 14:19:32 2017 fun2 finish Mon Jun 05 14:19:38 2017 finish 10.1229999065 Process finished with exit code 0
看,現(xiàn)在是先運(yùn)行fun1函數(shù),運(yùn)行完畢再運(yùn)行fun2接著再是print 'finish',即先運(yùn)行進(jìn)程p1再運(yùn)行進(jìn)程p2,感受到j(luò)oin()的魅力了吧.現(xiàn)在再試試注釋掉join()看看又會出現(xiàn)什么
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if __name__ == '__main__': a=time.time() p1=Process(target=fun1,args=(4,)) p2 = Process(target=fun2, args=(6,)) p1.start() p2.start() p1.join() #p2.join() b=time.time() print 'finish',b-a
結(jié)果:
this is fun1 Mon Jun 05 14:23:57 2017 this is fun2 Mon Jun 05 14:23:58 2017 fun1 finish Mon Jun 05 14:24:01 2017 finish 4.05900001526 fun2 finish Mon Jun 05 14:24:04 2017 Process finished with exit code 0
這次是運(yùn)行完fun1(因?yàn)閜1進(jìn)程有用join(),所以主程序等待p1運(yùn)行完接著執(zhí)行下一步),接著繼續(xù)運(yùn)行主進(jìn)程的print 'finish',最后fun2運(yùn)行完畢才結(jié)束
2.name,daemon,is_alive():
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if __name__ == '__main__': a=time.time() p1=Process(name='fun1進(jìn)程',target=fun1,args=(4,)) p2 = Process(name='fun2進(jìn)程',target=fun2, args=(6,)) p1.daemon=True p2.daemon = True p1.start() p2.start() p1.join() print p1,p2 print '進(jìn)程1:',p1.is_alive(),'進(jìn)程2:',p2.is_alive() #p2.join() b=time.time() print 'finish',b-a
結(jié)果:
this is fun2 Mon Jun 05 14:43:49 2017 this is fun1 Mon Jun 05 14:43:49 2017 fun1 finish Mon Jun 05 14:43:53 2017 <Process(fun1進(jìn)程, stopped daemon)> <Process(fun2進(jìn)程, started daemon)> 進(jìn)程1: False 進(jìn)程2: True finish 4.06500005722 Process finished with exit code 0
可以看到,name是給進(jìn)程賦予名字, 運(yùn)行到print '進(jìn)程1:',p1.is_alive(),'進(jìn)程2:',p2.is_alive() 這句的時候,p1進(jìn)程已經(jīng)結(jié)束(返回False),p2進(jìn)程仍然在運(yùn)行(返回True),但p2沒有用join(),所以直接接著執(zhí)行主進(jìn)程,由于用了daemon=Ture,父進(jìn)程終止后自動終止,p2進(jìn)程沒有結(jié)束就強(qiáng)行結(jié)束整個程序了.
3.run()
run()在Process沒有指定target函數(shù)時,默認(rèn)用run()函數(shù)運(yùn)行程序,
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if __name__ == '__main__': a = time.time() p=Process() p.start() p.join() b = time.time() print 'finish', b - a
結(jié)果:
finish 0.0840001106262
從結(jié)果看出,進(jìn)程p什么也沒做,為了讓進(jìn)程正常運(yùn)行,我們醬紫寫:
目標(biāo)函數(shù)沒有參數(shù):
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(): print 'this is fun1',time.ctime() time.sleep(2) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if __name__ == '__main__': a = time.time() p=Process() p.run=fun1 p.start() p.join() b = time.time() print 'finish', b - a
結(jié)果:
this is fun1 Mon Jun 05 16:34:41 2017 fun1 finish Mon Jun 05 16:34:43 2017 finish 2.11500000954 Process finished with exit code 0
目標(biāo)函數(shù)有參數(shù):
# -*- coding:utf-8 -*- from multiprocessing import Process import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if __name__ == '__main__': a = time.time() p=Process() p.run=fun1(2) p.start() p.join() b = time.time() print 'finish', b - a
結(jié)果:
this is fun1 Mon Jun 05 16:36:27 2017 fun1 finish Mon Jun 05 16:36:29 2017 Process Process-1: Traceback (most recent call last): File "E:\Anaconda2\lib\multiprocessing\process.py", line 258, in _bootstrap self.run() TypeError: 'NoneType' object is not callable finish 2.0529999733 Process finished with exit code 0
目標(biāo)函數(shù)有參數(shù)的出現(xiàn)了異常,為什么呢?我現(xiàn)在還找不到原因,但是實(shí)踐發(fā)現(xiàn),當(dāng)最后一個參數(shù)賦予進(jìn)程運(yùn)行后,沒有其他參數(shù),就會出現(xiàn)這個異常,有人知道的望告知.
二.進(jìn)程池
對于需要使用幾個甚至十幾個進(jìn)程時,我們使用Process還是比較方便的,但是如果要成百上千個進(jìn)程,用Process顯然太笨了,multiprocessing提供了Pool類,即現(xiàn)在要講的進(jìn)程池,能夠?qū)⒈姸噙M(jìn)程放在一起,設(shè)置一個運(yùn)行進(jìn)程上限,每次只運(yùn)行設(shè)置的進(jìn)程數(shù),等有進(jìn)程結(jié)束,再添加新的進(jìn)程
Pool(processes =num):設(shè)置運(yùn)行進(jìn)程數(shù),當(dāng)一個進(jìn)程運(yùn)行完,會添加新的進(jìn)程進(jìn)去
apply_async(函數(shù),(參數(shù))):非阻塞,其中參數(shù)是tulpe類型,
apply(函數(shù),(參數(shù))):阻塞
close():關(guān)閉pool,不能再添加新的任務(wù)
terminate():結(jié)束運(yùn)行的進(jìn)程,不再處理未完成的任務(wù)
join():和Process介紹的作用一樣, 但要在close或terminate之后使用。
1.單個進(jìn)程池
# -*- coding:utf-8 -*- from multiprocessing import Pool import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if __name__ == '__main__': a=time.time() pool = Pool(processes =3) # 可以同時跑3個進(jìn)程 for i in range(3,8): pool.apply_async(fun1,(i,)) pool.close() pool.join() b=time.time() print 'finish',b-a
結(jié)果:
this is fun1 Mon Jun 05 15:15:38 2017 this is fun1 Mon Jun 05 15:15:38 2017 this is fun1 Mon Jun 05 15:15:38 2017 fun1 finish Mon Jun 05 15:15:41 2017 this is fun1 Mon Jun 05 15:15:41 2017 fun1 finish Mon Jun 05 15:15:42 2017 this is fun1 Mon Jun 05 15:15:42 2017 fun1 finish Mon Jun 05 15:15:43 2017 fun1 finish Mon Jun 05 15:15:47 2017 fun1 finish Mon Jun 05 15:15:49 2017 finish 11.1370000839 Process finished with exit code 0
從上面的結(jié)果可以看到,設(shè)置了3個運(yùn)行進(jìn)程上限,15:15:38這個時間同時開始三個進(jìn)程,當(dāng)?shù)谝粋€進(jìn)程結(jié)束時(參數(shù)為3秒那個進(jìn)程),會添加新的進(jìn)程,如此循環(huán),直至進(jìn)程池運(yùn)行完再執(zhí)行主進(jìn)程語句b=time.time() print 'finish',b-a .這里用到非阻塞apply_async(),再來對比下阻塞apply()
# -*- coding:utf-8 -*- from multiprocessing import Pool import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if __name__ == '__main__': a=time.time() pool = Pool(processes =3) # 可以同時跑3個進(jìn)程 for i in range(3,8): pool.apply(fun1,(i,)) pool.close() pool.join() b=time.time() print 'finish',b-a
結(jié)果:
this is fun1 Mon Jun 05 15:59:26 2017 fun1 finish Mon Jun 05 15:59:29 2017 this is fun1 Mon Jun 05 15:59:29 2017 fun1 finish Mon Jun 05 15:59:33 2017 this is fun1 Mon Jun 05 15:59:33 2017 fun1 finish Mon Jun 05 15:59:38 2017 this is fun1 Mon Jun 05 15:59:38 2017 fun1 finish Mon Jun 05 15:59:44 2017 this is fun1 Mon Jun 05 15:59:44 2017 fun1 finish Mon Jun 05 15:59:51 2017 finish 25.1610000134 Process finished with exit code 0
可以看到,阻塞是當(dāng)一個進(jìn)程結(jié)束后,再進(jìn)行下一個進(jìn)程,一般我們都用非阻塞apply_async()
2.多個進(jìn)程池
上面是使用單個進(jìn)程池的,對于多個進(jìn)程池,我們可以用for循環(huán),直接看代碼
# -*- coding:utf-8 -*- from multiprocessing import Pool import time def fun1(t): print 'this is fun1',time.ctime() time.sleep(t) print 'fun1 finish',time.ctime() def fun2(t): print 'this is fun2',time.ctime() time.sleep(t) print 'fun2 finish',time.ctime() if __name__ == '__main__': a=time.time() pool = Pool(processes =3) # 可以同時跑3個進(jìn)程 for fun in [fun1,fun2]: for i in range(3,8): pool.apply_async(fun,(i,)) pool.close() pool.join() b=time.time() print 'finish',b-a
結(jié)果:
this is fun1 Mon Jun 05 16:04:38 2017 this is fun1 Mon Jun 05 16:04:38 2017 this is fun1 Mon Jun 05 16:04:38 2017 fun1 finish Mon Jun 05 16:04:41 2017 this is fun1 Mon Jun 05 16:04:41 2017 fun1 finish Mon Jun 05 16:04:42 2017 this is fun1 Mon Jun 05 16:04:42 2017 fun1 finish Mon Jun 05 16:04:43 2017 this is fun2 Mon Jun 05 16:04:43 2017 fun2 finish Mon Jun 05 16:04:46 2017 this is fun2 Mon Jun 05 16:04:46 2017 fun1 finish Mon Jun 05 16:04:47 2017 this is fun2 Mon Jun 05 16:04:47 2017 fun1 finish Mon Jun 05 16:04:49 2017 this is fun2 Mon Jun 05 16:04:49 2017 fun2 finish Mon Jun 05 16:04:50 2017 this is fun2 Mon Jun 05 16:04:50 2017 fun2 finish Mon Jun 05 16:04:52 2017 fun2 finish Mon Jun 05 16:04:55 2017 fun2 finish Mon Jun 05 16:04:57 2017 finish 19.1670000553 Process finished with exit code 0
看到了,在fun1運(yùn)行完接著運(yùn)行fun2.
另外對于沒有參數(shù)的情況,就直接 pool.apply_async(funtion),無需寫上參數(shù).
在學(xué)習(xí)編寫程序過程,曾遇到不用if _name_ == '_main_':而直接運(yùn)行程序,這樣結(jié)果會出錯,經(jīng)查詢,在Windows上要想使用進(jìn)程模塊,就必須把有關(guān)進(jìn)程的代碼寫在當(dāng)前.py文件的if _name_ == ‘_main_' :語句的下面,才能正常使用Windows下的進(jìn)程模塊。Unix/Linux下則不需要。原因有人這么說:在執(zhí)行的時候,由于你寫的 py 會被當(dāng)成module 讀進(jìn)執(zhí)行。所以,一定要判斷自身是否為 _main_。也就是要:
if __name__ == ‘__main__' : # do something.
這里我自己還搞不清楚,期待以后能夠理解
學(xué)習(xí)的過程中,還涉及了經(jīng)常和進(jìn)程一起運(yùn)用的隊(duì)列Queue和線程threading,有時間以后再寫吧,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Python多進(jìn)程multiprocessing、進(jìn)程池用法實(shí)例分析
- python進(jìn)程池實(shí)現(xiàn)的多進(jìn)程文件夾copy器完整示例
- python多進(jìn)程(加入進(jìn)程池)操作常見案例
- Python多進(jìn)程池 multiprocessing Pool用法示例
- Python多進(jìn)程庫multiprocessing中進(jìn)程池Pool類的使用詳解
- Python 多進(jìn)程并發(fā)操作中進(jìn)程池Pool的實(shí)例
- Python基于進(jìn)程池實(shí)現(xiàn)多進(jìn)程過程解析
相關(guān)文章
python3 使用函數(shù)求兩個數(shù)的和與差
這篇文章主要介紹了python3 使用函數(shù)求兩個數(shù)的和與差,具有很好的參考價值,希望對大家有所幫助。2021-05-05python生成多個只含0,1元素的隨機(jī)數(shù)組或列表的實(shí)例
今天小編就為大家分享一篇python生成多個只含0,1元素的隨機(jī)數(shù)組或列表的實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-11-11pytorch中如何使用DataLoader對數(shù)據(jù)集進(jìn)行批處理的方法
這篇文章主要介紹了pytorch中如何使用DataLoader對數(shù)據(jù)集進(jìn)行批處理的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08Python實(shí)現(xiàn)將字典(列表按列)存入csv文件
這篇文章主要介紹了Python實(shí)現(xiàn)將字典(列表按列)存入csv文件方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06Python實(shí)現(xiàn)特定場景去除高光算法詳解
這篇文章主要介紹了如何利用Python+OpenCV實(shí)現(xiàn)特定場景去除高光算法,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Python有一定的幫助,需要的可以參考一下2021-12-12詳談Python 窗體(tkinter)表格數(shù)據(jù)(Treeview)
今天小編就為大家分享一篇詳談Python 窗體(tkinter)表格數(shù)據(jù)(Treeview),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10