通過實例解析python創(chuàng)建進(jìn)程常用方法
運行程序時,單線程或單進(jìn)程往往是比較慢的,為加快程序運行速度,我們可以使用多進(jìn)程,可以理解為多任務(wù)同時運行,小編的電腦是四核,所以可以設(shè)置四個進(jìn)程。
下面,我們來了解下多進(jìn)程的使用:
1、使用multiprocessing模塊創(chuàng)建進(jìn)程
multiprocessing模塊提供了一個Process類來代表進(jìn)程對象,語法如下:
Process([group[,target[,name[,args[,kwargs]]]]])
其中,group:參數(shù)未使用,值始終是None
target:表示當(dāng)前進(jìn)程啟動時執(zhí)行的可調(diào)用對象
name:為當(dāng)前進(jìn)程實例的別名
args:表示傳遞給target函數(shù)的參數(shù)元組
kwargs:表示傳遞給target函數(shù)的參數(shù)字典
使用多進(jìn)程的一個簡單例子:
from multiprocessing import Process # 導(dǎo)入模塊 # 執(zhí)行子進(jìn)程代碼 def test(interval): print('我是子進(jìn)程') # 執(zhí)行主程序 def main(): print('主進(jìn)程開始') # 實例化Procss進(jìn)程類 p = Process(target=test,args=(1,)) # 啟動子進(jìn)程 p.start() print('主進(jìn)程結(jié)束') if __name__ == '__main__': main()
結(jié)果:
主進(jìn)程開始
主進(jìn)程結(jié)束
我是子進(jìn)程
Process的實例p常用的方法除start()外,還有如下常用方法:
is_alive():判斷進(jìn)程實例是否還在執(zhí)行
join([timeout]):是否等待進(jìn)程實例執(zhí)行結(jié)束,或等待多少秒
start():啟動進(jìn)程實例(創(chuàng)建子進(jìn)程)
run():如果沒有給定target參數(shù),對這個對象調(diào)用start()方法時,就將執(zhí)行對象中的run()方法
terminate():不管任務(wù)是否完成,立即終止
Process類還有如下常用屬性:
name:當(dāng)前進(jìn)程實例別名,默認(rèn)為Process-N,N為從1開始遞增的整數(shù)
pid:當(dāng)前進(jìn)程實例的PID值
下面是Process類方法和屬性的使用,創(chuàng)建兩個子進(jìn)程,分別使用os模塊和time模塊輸出父進(jìn)程和子進(jìn)程的id以及子進(jìn)程的時間,并調(diào)用Process類的name和pid屬性:
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os #兩個子進(jìn)程將會調(diào)用的兩個方法 def child_1(interval): print("子進(jìn)程(%s)開始執(zhí)行,父進(jìn)程為(%s)" % (os.getpid(), os.getppid())) # 計時開始 t_start = time.time() # 程序?qū)粧炱餴nterval秒 time.sleep(interval) # 計時結(jié)束 t_end = time.time() print("子進(jìn)程(%s)執(zhí)行時間為'%0.2f'秒"%(os.getpid(),t_end - t_start)) def child_2(interval): print("子進(jìn)程(%s)開始執(zhí)行,父進(jìn)程為(%s)" % (os.getpid(), os.getppid())) # 計時開始 t_start = time.time() # 程序?qū)粧炱餴nterval秒 time.sleep(interval) # 計時結(jié)束 t_end = time.time() print("子進(jìn)程(%s)執(zhí)行時間為'%0.2f'秒"%(os.getpid(),t_end - t_start)) if __name__ == '__main__': print("------父進(jìn)程開始執(zhí)行-------") # 輸出當(dāng)前程序的ID print("父進(jìn)程PID:%s" % os.getpid()) # 實例化進(jìn)程p1 p1=Process(target=child_1,args=(1,)) # 實例化進(jìn)程p2 p2=Process(target=child_2,name="mrsoft",args=(2,)) # 啟動進(jìn)程p1 p1.start() # 啟動進(jìn)程p2 p2.start() #同時父進(jìn)程仍然往下執(zhí)行,如果p2進(jìn)程還在執(zhí)行,將會返回True print("p1.is_alive=%s"%p1.is_alive()) print("p2.is_alive=%s"%p2.is_alive()) #輸出p1和p2進(jìn)程的別名和PID print("p1.name=%s"%p1.name) print("p1.pid=%s"%p1.pid) print("p2.name=%s"%p2.name) print("p2.pid=%s"%p2.pid) print("------等待子進(jìn)程-------") # 等待p1進(jìn)程結(jié)束 p1.join() # 等待p2進(jìn)程結(jié)束 p2.join() print("------父進(jìn)程執(zhí)行結(jié)束-------")
結(jié)果:
------父進(jìn)程開始執(zhí)行------- 父進(jìn)程PID:13808 p1.is_alive=True p2.is_alive=True p1.name=Process-1 p1.pid=13360 p2.name=mrsoft p2.pid=21500 ------等待子進(jìn)程------- 子進(jìn)程(13360)開始執(zhí)行,父進(jìn)程為(13808) 子進(jìn)程(21500)開始執(zhí)行,父進(jìn)程為(13808) 子進(jìn)程(13360)執(zhí)行時間為'1.01'秒 子進(jìn)程(21500)執(zhí)行時間為'2.00'秒 ------父進(jìn)程執(zhí)行結(jié)束-------
上述代碼中,第一次實例化Process類時,會為name屬性默認(rèn)賦值為Process-1,第二次則默認(rèn)為Process-2,但由于實例化進(jìn)程p2時,設(shè)置了name屬性為mrsoft,所以p2.name的值為mrsoft。
2、使用Process子類創(chuàng)建進(jìn)程
對于一些簡單的小任務(wù),通常使用Process(target=test)方式實現(xiàn)多進(jìn)程。但如果要處理復(fù)雜任務(wù)的進(jìn)程,通常定義一個類,使其繼承Process類,下面是通過使用Process子類創(chuàng)建多個進(jìn)程。
# -*- coding:utf-8 -*- from multiprocessing import Process import time import os #繼承Process類 class SubProcess(Process): # 由于Process類本身也有__init__初識化方法,這個子類相當(dāng)于重寫了父類的這個方法 def __init__(self,interval,name=''): # 調(diào)用Process父類的初始化方法 Process.__init__(self) # 接收參數(shù)interval self.interval = interval # 判斷傳遞的參數(shù)name是否存在 if name: # 如果傳遞參數(shù)name,則為子進(jìn)程創(chuàng)建name屬性,否則使用默認(rèn)屬性 self.name = name #重寫了Process類的run()方法 def run(self): print("子進(jìn)程(%s) 開始執(zhí)行,父進(jìn)程為(%s)"%(os.getpid(),os.getppid())) t_start = time.time() time.sleep(self.interval) t_stop = time.time() print("子進(jìn)程(%s)執(zhí)行結(jié)束,耗時%0.2f秒"%(os.getpid(),t_stop-t_start)) if __name__=="__main__": print("------父進(jìn)程開始執(zhí)行-------") # 輸出當(dāng)前程序的ID print("父進(jìn)程PID:%s" % os.getpid()) p1 = SubProcess(interval=1,name='mrsoft') p2 = SubProcess(interval=2) #對一個不包含target屬性的Process類執(zhí)行start()方法,就會運行這個類中的run()方法, #所以這里會執(zhí)行p1.run() # 啟動進(jìn)程p1 p1.start() # 啟動進(jìn)程p2 p2.start() # 輸出p1和p2進(jìn)程的執(zhí)行狀態(tài),如果真正進(jìn)行,返回True,否則返回False print("p1.is_alive=%s"%p1.is_alive()) print("p2.is_alive=%s"%p2.is_alive()) #輸出p1和p2進(jìn)程的別名和PID print("p1.name=%s"%p1.name) print("p1.pid=%s"%p1.pid) print("p2.name=%s"%p2.name) print("p2.pid=%s"%p2.pid) print("------等待子進(jìn)程-------") # 等待p1進(jìn)程結(jié)束 p1.join() # 等待p2進(jìn)程結(jié)束 p2.join() print("------父進(jìn)程執(zhí)行結(jié)束-------")
結(jié)果:
------父進(jìn)程開始執(zhí)行------- 父進(jìn)程PID:2512 p1.is_alive=True p2.is_alive=True p1.name=mrsoft p1.pid=20328 p2.name=SubProcess-2 p2.pid=13700 ------等待子進(jìn)程------- 子進(jìn)程(20328) 開始執(zhí)行,父進(jìn)程為(2512) 子進(jìn)程(13700) 開始執(zhí)行,父進(jìn)程為(2512) 子進(jìn)程(20328)執(zhí)行結(jié)束,耗時1.00秒 子進(jìn)程(13700)執(zhí)行結(jié)束,耗時2.00秒 ------父進(jìn)程執(zhí)行結(jié)束-------
上述代碼中,定義了一個SubProcess子類,繼承multiprocess.Process父類。SubProcess子類中定義了兩個方法:__init__()初始化方法和run()方法,在__init__()初始化方法中,調(diào)用父類multiprocess.Process的__init__()初始化方法,否則父類的__init__()方法會被覆蓋,無法開啟進(jìn)程。此外,在SubProcess子類中沒有定義start()方法,但在主程序中卻調(diào)用了start()方法,此時就會自動執(zhí)行SubProcess類的run()方法。
3、使用進(jìn)程池Pool創(chuàng)建進(jìn)程
上面我們使用Process類創(chuàng)建了兩個進(jìn)程,但如果要創(chuàng)建十幾個或者上百個進(jìn)程,則需要實例化更多的Process類,解決這一問題的方法就是使用multiprocessing模塊提供的pool類,即Pool進(jìn)程池。
我們先來了解下Pool類的常用方法:
apply_async(func[,args[,kwds]]):使用非阻塞方式調(diào)用func()函數(shù)(并行執(zhí)行,阻塞方式必須等待上一個進(jìn)程退出才能執(zhí)行下一個進(jìn)程),args為傳遞給func()函數(shù)的參數(shù)列表, kwds為傳遞給func()函數(shù)的關(guān)鍵字參數(shù)列表
apply(func[,args[,kwds]]):使用阻塞方式調(diào)用func()函數(shù)
close():關(guān)閉Pool,使其不再接受新的任務(wù)
terminate():不管任務(wù)是否完成,立即終止
join():主進(jìn)程阻塞,等待子進(jìn)程的退出,必須在close或terminate之后使用
下面通過一個示例演示一下如何通過進(jìn)程池創(chuàng)建多進(jìn)程,設(shè)置最大進(jìn)程數(shù)為3,使用非阻塞方式執(zhí)行10個任務(wù):
# -*- coding=utf-8 -*- from multiprocessing import Pool import os, time def task(name): print('子進(jìn)程(%s)執(zhí)行task %s ...' % ( os.getpid() ,name)) # 休眠1秒 time.sleep(1) if __name__=='__main__': print('父進(jìn)程(%s).' % os.getpid()) # 定義一個進(jìn)程池,最大進(jìn)程數(shù)3 p = Pool(3) # 從0開始循環(huán)10次 for i in range(10): # 使用非阻塞方式調(diào)用task()函數(shù) p.apply_async(task, args=(i,)) print('等待所有子進(jìn)程結(jié)束...') # 關(guān)閉進(jìn)程池,關(guān)閉后p不再接收新的請求 p.close() # 等待子進(jìn)程結(jié)束 p.join() print('所有子進(jìn)程結(jié)束.')
結(jié)果:
父進(jìn)程(3856). 等待所有子進(jìn)程結(jié)束... 子進(jìn)程(18872)執(zhí)行task 0 ... 子進(jìn)程(11220)執(zhí)行task 1 ... 子進(jìn)程(10140)執(zhí)行task 2 ... 子進(jìn)程(18872)執(zhí)行task 3 ... 子進(jìn)程(11220)執(zhí)行task 4 ... 子進(jìn)程(10140)執(zhí)行task 5 ... 子進(jìn)程(18872)執(zhí)行task 6 ... 子進(jìn)程(11220)執(zhí)行task 7 ... 子進(jìn)程(10140)執(zhí)行task 8 ... 子進(jìn)程(18872)執(zhí)行task 9 ... 所有子進(jìn)程結(jié)束.
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- python 進(jìn)程的幾種創(chuàng)建方式詳解
- 對Python中創(chuàng)建進(jìn)程的兩種方式以及進(jìn)程池詳解
- python基于multiprocessing的多進(jìn)程創(chuàng)建方法
- python創(chuàng)建進(jìn)程fork用法
- Python使用multiprocessing創(chuàng)建進(jìn)程的方法
- python在windows下創(chuàng)建隱藏窗口子進(jìn)程的方法
- Python 創(chuàng)建子進(jìn)程模塊subprocess詳解
- 小結(jié)Python用fork來創(chuàng)建子進(jìn)程注意事項
相關(guān)文章
python簡單幾步實現(xiàn)時間日期處理到數(shù)據(jù)文件的讀寫
這篇文章主要為大家介紹了python簡單幾步實現(xiàn)時間日期處理到數(shù)據(jù)文件的讀寫詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04在python下實現(xiàn)word2vec詞向量訓(xùn)練與加載實例
這篇文章主要介紹了在python下實現(xiàn)word2vec詞向量訓(xùn)練與加載實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-06-06python學(xué)習(xí)print中format的用法示例
這篇文章主要為大家介紹了python學(xué)習(xí)print中format的用法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03python算法與數(shù)據(jù)結(jié)構(gòu)朋友圈與水杯實驗題分析實例
這篇文章主要介紹了python算法與數(shù)據(jù)結(jié)構(gòu)朋友圈與水杯實驗題分析,總的來說這并不是難題,那為什么要拿出這道題介紹?拿出這道題真正想要傳達(dá)的是解題的思路,以及不斷優(yōu)化探尋最優(yōu)解的過程。希望通過這道題能給你帶來一種解題優(yōu)化的思路2022-12-12