Ⅰ python並發編程之多進程方式(multiprocessing模塊)
Python的並發編程提供了多進程方式來提高效率,通過multiprocessing模塊實現。下面將詳細闡述進程與線程的區別,以及如何使用多進程來優化任務執行。
在並發編程中,進程就像工廠的車間,每個車間運行一個獨立的線程,即工人。為了提升生產效率,我們需要理解進程和線程的協作與獨立性。
首先,我們通過串列執行程序,將兩個數值傳遞給func函數,逐個處理。這展示了單進程的工作方式,隨後引入多進程。Python的multiprocessing模塊允許我們創建多個並行運行的進程。通過Process類,我們創建子進程,它們獨立於主進程,沒有執行順序,如下面的代碼所示:
python
import multiprocessing as mp
# 創建子進程
p1 = mp.Process(target=func, args=(數值1,))
p2 = mp.Process(target=func, args=(數值2,))
主進程在子進程啟動後繼續執行,由於子進程各自獨立輪詢,主進程完成的時間會早於子進程。當子進程輪詢序列相同時,它們會同時完成,如代碼中所述:
python
# 使用join方法等待子進程結束
p1.start()
p2.start()
p1.join()
p2.join()
在實際應用中,尤其是需要處理大量數據或任務的場景,我們可以使用循環來創建多個子進程,以進一步提高效率。通過多進程方式,Python為我們提供了一種高效且靈活的並發解決方案。
Ⅱ python最多開多少進程(python多進程)
導讀:今天首席CTO筆記來給各位分享關於python最多開多少進程的相關內容,如果能碰巧解決你現在面臨的問題,別忘了關注本站,現在開始吧!
pythonmultiprocessing最大多少進程最大進程只受操作系統資源限制.
不是進程越多越好,程序的速度就越快.
一般有幾個CPU核心,就開多少進程,或者核心數的N倍.
python進程池最大數量初始化Pool時,可以指定一個最大進程數,當有新的請求提交到Pool中時,如果池還沒有滿,那麼就會創建一個新的進程用來執行該請求;但如果池中的進程數已經達到指定的最大值,那麼該請求就會等待,直到池中有進程結束,才會用之前的進程來執行新的任務。
python最大支持多少線程
python線程太慢了,想並發去用greenlet吧,快,寫起來還方便。
如果加鎖同步的話,線程多了反而變慢也有可能。
ulimit-s返回線程棧大小,我的默認是8192,用內存大小除以它就得到理論上的線程數吧。
python之多線程進程的概念:以一個整體的形式暴露給操作系統管理,裡麵包含各種資源的調用。對各種資源管理的集合就可以稱為進程。
線程的概念:是操作系統能夠進行運算調度的最小單位。本質上就是一串指令的集合。
進程和線程的區別:
1、線程共享內存空間,進程有獨立的內存空間。
2、線程啟動速度快,進程啟動速度慢。注意:二者的運行速度是無法比較的。
3、線程是執行的指令集,進程是資源的集合
4、兩個子進程之間數據不共享,完全獨立。同一個進程下的線程共享同一份數據。
5、創建新的線程很簡單,創建新的進程需要對他的父進程進行一次克隆。
6、一個線程可以操作(控制)同一進程里的其他線程,但是進程只能操作子進程
7、同一個進程的線程可以直接交流,兩個進程想要通信,必須通過一個中間代理來實現。
8、對於線程的修改,可能會影響到其他線程的行為。但是對於父進程的修改不會影響到子進程。
第一個程序,使用循環來創建線程,但是這個程序中一共有51個線程,我們創建了50個線程,但是還有一個程序本身的線程,是主線程。這51個線程是並行的。注意:這個程序中是主線程啟動了子線程。
相比上個程序,這個程序多了一步計算時間,但是我們觀察結果會發現,程序顯示的執行時間只有0.007秒,這是因為最後一個print函數它存在於主線程,而整個程序主線程和所有子線程是並行的,那麼可想而知,在子線程還沒有執行完畢的時候print函數就已經執行了,總的來說,這個時間只是執行了一個線程也就是主線程所用的時間。
接下來這個程序,吸取了上面這個程序的缺點,創建了一個列表,把所有的線程實例都存進去,然後使用一個for循環依次對線程實例調用join方法,這樣就可以使得主線程等待所創建的所有子線程執行完畢才能往下走。注意實驗結果:和兩個線程的結果都是兩秒多一點
注意觀察實驗結果,並沒有執行列印taskhasdone,並且程序執行時間極其短。
這是因為在主線程啟動子線程前把子線程設置為守護線程。
只要主線程執行完畢,不管子線程是否執行完畢,就結束。但是會等待非守護線程執行完畢
主線程退出,守護線程全部強制退出。皇帝死了,僕人也跟著殉葬
應用的場景:socket-server
注意:gil只是為了減低程序開發復雜度。但是在2.幾的版本上,需要加用戶態的鎖(gil的缺陷)而在3點幾的版本上,加鎖不加鎖都一樣。
下面這個程序是一個典型的生產者消費者模型。
生產者消費者模型是經典的在開發架構中使用的模型
運維中的集群就是生產者消費者模型,生活中很多都是
那麼,多線程的使用場景是什麼?
python中的多線程實質上是對上下文的不斷切換,可以說是假的多線程。而我們知道,io操作不佔用cpu,計算佔用cpu,那麼python的多線程適合io操作密集的任務,比如socket-server,那麼cpu密集型的任務,python怎麼處理?python可以折中的利用計算機的多核:啟動八個進程,每個進程有一個線程。這樣就可以利用多進程解決多核問題。
python多開是多進程嗎python多開是多進程。根據查詢相關公開信息顯示,多進程類似於多開應用,屬於真正的多核任務,各個進程有獨立的資源分配,因此跨進程內存共享需要有專用多進程庫支持。
python可以多進程嗎想要充分利用多核CPU資源,Python中大部分情況下都需要使用多進程,Python中提供了multiprocessing這個包實現多進程。multiprocessing支持子進程、進程間的同步與通信,提供了Process、Queue、Pipe、Lock等組件。
開辟子進程
multiprocessing中提供了Process類來生成進程實例
Process([group[,target[,name[,args[,kwargs]]]]])
group分組,實際上不使用
target表示調用對象,你可以傳入方法的名字
args表示給調用對象以元組的形式提供參數,比如target是函數a,他有兩個參數m,n,那麼該參數為args=(m,n)即可
kwargs表示調用對象的字典
name是別名,相當於給這個進程取一個名字
先來個小例子:
#-*-coding:utf-8-*-
,Pool
importos
importtime
defrun_proc(wTime):
n=0
whilen3:
print"subProcess%srun,"%os.getpid(),"{0}".format(time.ctime())#獲取當前進程號和正在運行是的時間
time.sleep(wTime)#等待(休眠)
n+=1
if__name__=="__main__":
p=Process(target=run_proc,args=(2,))#申請子進程
p.start()#運行進程
print"Parentprocessrun.subProcessis",p.pid
print"Parentprocessend,{0}".format(time.ctime())
運行結果:
Parentprocessrun.subProcessis30196
Parentprocessend,MonMar2711:20:212017
subProcess30196run,MonMar2711:20:212017
subProcess30196run,MonMar2711:20:232017
subProcess30196run,MonMar2711:20:252017
根據運行結果可知,父進程運行結束後子進程仍然還在運行,這可能造成僵屍(zombie)進程。
通常情況下,當子進程終結時,它會通知父進程,清空自己所佔據的內存,並在內核里留下自己的退出信息。父進程在得知子進程終結時,會從內核中取出子進程的退出信息。但是,如果父進程早於子進程終結,這可能造成子進程的退出信息滯留在內核中,子進程成為僵屍(zombie)進程。當大量僵屍進程積累時,內存空間會被擠占。
有什麼辦法可以避免僵屍進程呢?
這里介紹進程的一個屬性deamon,當其值為TRUE時,其父進程結束,該進程也直接終止運行(即使還沒運行完)。
所以給上面的程序加上p.deamon=true,看看效果。
#-*-coding:utf-8-*-
,Pool
importos
importtime
defrun_proc(wTime):
n=0
whilen3:
print"subProcess%srun,"%os.getpid(),"{0}".format(time.ctime())
time.sleep(wTime)
n+=1
if__name__=="__main__":
p=Process(target=run_proc,args=(2,))
p.daemon=True#加入daemon
p.start()
print"Parentprocessrun.subProcessis",p.pid
print"Parentprocessend,{0}".format(time.ctime())
執行結果:
Parentprocessrun.subProcessis31856
Parentprocessend,MonMar2711:40:102017
這是問題又來了,子進程並沒有執行完,這不是所期望的結果。有沒辦法將子進程執行完後才讓父進程結束呢?
這里引入p.join()方法,它使子進程執行結束後,父進程才執行之後的代碼
#-*-coding:utf-8-*-
,Pool
importos
importtime
defrun_proc(wTime):
n=0
whilen3:
print"subProcess%srun,"%os.getpid(),"{0}".format(time.ctime())
time.sleep(wTime)
n+=1
if__name__=="__main__":
p=Process(target=run_proc,args=(2,))
p.daemon=True
p.start()
p.join()#加入join方法
print"Parentprocessrun.subProcessis",p.pid
print"Parentprocessend,{0}".format(time.ctime())
執行結果:
subProcess32076run,MonMar2711:46:072017
subProcess32076run,MonMar2711:46:092017
subProcess32076run,MonMar2711:46:112017
Parentprocessrun.subProcessis32076
Parentprocessend,MonMar2711:46:132017
這樣所有的進程就能順利的執行了。
結語:以上就是首席CTO筆記為大家整理的關於python最多開多少進程的相關內容解答匯總了,希望對您有所幫助!如果解決了您的問題歡迎分享給更多關注此問題的朋友喔~
Ⅲ Python中進程multiprocessing用法詳解
一、multiprocessing模塊
multiprocessing模塊提供了一個Process類來代表一個進程對象,multiprocessing模塊像線程一樣管理進程,這個是multiprocessing的核心,它與threading很相似,對多核CPU的利用率會比threading好的多
看一下Process類的構造方法:
__init__(self,group=None,target=None,name=None,args=(),kwargs={})參數說明:
group:進程所屬組(基本不用)
target:表示調用對象
args:表示調用對象的位置參數元組
name:別名
kwargs:表示調用對象的字典
importmultiprocessingdefdo(n):#參數n由args=(1,)傳入name=multiprocessing.current_process().name#獲取當前進程的名字print(name,'starting')print("worker",n)returnif__name__=='__main__':numList=[]foriinrange(5):p=multiprocessing.Process(target=do,args=(i,))#(i,)中加入","表示元祖numList.append(p)print(numList)p.start()#用start()方法啟動進程,執行do()方法p.join()#等待子進程結束以後再繼續往下運行,通常用於進程間的同步print("Processend.")運行結果如下:
[<Process(Process-1,initial)>]Process-1startingworker0Processend.[<Process(Process-1,stopped)>,<Process(Process-2,initial)>]Process-2startingworker1Processend.[<Process(Process-1,stopped)>,<Process(Process-2,stopped)>,<Process(Process-3,initial)>]Process-3startingworker2Processend.[<Process(Process-1,stopped)>,<Process(Process-2,stopped)>,<Process(Process-3,stopped)>,<Process(Process-4,initial)>]Process-4startingworker3Processend.[<Process(Process-1,stopped)>,<Process(Process-2,stopped)>,<Process(Process-3,stopped)>,<Process(Process-4,stopped)>,<Process(Process-5,initial)>]Process-5startingworker4Processend.通過列印numList可以看出當前進程結束後,再開始下一個進程
注意:在Windows上要想使用進程模塊,就必須把有關進程的代碼寫在當前.py文件的ifname==>『main』:語句的下面,才能正常使用Windows下的進程模塊。Unix/Linux下則不需要
二、Pool類
Pool類可以提供指定數量的進程供用戶調用,當有新的請求提交到Pool中時,如果池還沒有滿,就會創建一個新的進程來執行請求。如果池滿,請求就會告知先等待,直到池中有進程結束,才會創建新的進程來執行這些請求下面介紹一下multiprocessing模塊下的Pool類下的幾個方法:
1.apply()
函數原型:apply(func[,args=()[,kwds={}]])
該函數用於傳遞不定參數,同python中的apply函數一致,主進程會被阻塞直到函數執行結束(不建議使用,並且3.x以後不再出現)
2.apply_async
函數原型:apply_async(func[,args=()[,kwds={}[,callback=None]]])
與apply用法一致,但它是非阻塞的且支持結果返回後進行回調
3.map()
函數原型:map(func,iterable[,chunksize=None])
Pool類中的map方法,與內置的map函數用法行為基本一致,它會使進程阻塞直到結果返回注意:雖然第二個參數是一個迭代器,但在實際使用中,必須在整個隊列都就緒後,程序才會運行子進程
4.map_async()
函數原型:map_async(func,iterable[,chunksize[,callback]])與map用法一致,但是它是非阻塞的
5.close()
關閉進程池(pool),使其不再接受新的任務
6.terminal()
結束工作進程,不再處理未處理的任務
7.join()
主進程阻塞等待子進程的退出,join方法要在close或terminate之後使用
示例1--使用map()函數
(fn):#fn:函數參數是數據列表的一個元素time.sleep(1)print(fn*fn)if__name__=="__main__":testFL=[1,2,3,4,5,6]print('shunxu:')#順序執行(也就是串列執行,單進程)s=time.time()forfnintestFL:run(fn)t1=time.time()print("順序執行時間:",int(t1-s))print('concurrent:')#創建多個進程,並行執行pool=Pool(3)#創建擁有3個進程數量的進程池#testFL:要處理的數據列表,run:處理testFL列表中數據的函數pool.map(run,testFL)pool.close()#關閉進程池,不再接受新的進程pool.join()#主進程阻塞等待子進程的退出t2=time.time()print("並行執行時間:",int(t2-t1))1、map函數中testFL為可迭代對象--列表
2、當創建3個進程時,會一次列印出3個結果「1,4,9」,當當創建2個進程時,會一次列印出2個結果「1,4」,以此類推,當創建多餘6個進程時,會一次列印出所有結果
3、如果使用Pool(),不傳入參數,可以創建一個動態控制大小的進程池
從結果可以看出,並發執行的時間明顯比順序執行要快很多,但是進程是要耗資源的,所以平時工作中,進程數也不能開太大。對Pool對象調用join()方法會等待所有子進程執行完畢,調用join()之前必須先調用close(),讓其不再接受新的Process了
示例2--使用map()_async函數
print('concurrent:')#創建多個進程,並行執行pool=Pool(3)#創建擁有3個進程數量的進程池#testFL:要處理的數據列表,run:處理testFL列表中數據的函數pool.map_async(run,testFL)pool.close()#關閉進程池,不再接受新的進程pool.join()#主進程阻塞等待子進程的退出t2=time.time()print("並行執行時間:",int(t2-t1))從結果可以看出,map_async()和map()用時相同。目前還沒有看出兩者的區別,後面知道後再完善
示例3--使用apply()函數
print('concurrent:')#創建多個進程,並行執行pool=Pool(3)#創建擁有3個進程數量的進程池#testFL:要處理的數據列表,run:處理testFL列表中數據的函數forfnintestFL:pool.apply(run,(fn,))pool.close()#關閉進程池,不再接受新的進程pool.join()#主進程阻塞等待子進程的退出t2=time.time()print("並行執行時間:",int(t2-t1))可見,使用apply()方法,並行執行和順序執行用時相同,經過試驗,進程數目增大也不會減少並行執行的時間
原因:以阻塞的形式產生進程任務,生成1個任務進程並等它執行完出池,第2個進程才會進池,主進程一直阻塞等待,每次只執行1個進程任務
示例4--使用apply_async()函數
print('concurrent:')#創建多個進程,並行執行pool=Pool(3)#創建擁有3個進程數量的進程池#testFL:要處理的數據列表,run:處理testFL列表中數據的函數forfnintestFL:pool.apply_async(run,(fn,))pool.close()#關閉進程池,不再接受新的進程pool.join()#主進程阻塞等待子進程的退出t2=time.time()print("並行執行時間:",int(t2-t1))可見,使用apply_async()方法,並行執行時間與使用map()、map_async()方法相同
注意:
map_async()和map()方法,第2個參數可以是列表也可以是元祖,如下圖:
而使用apply()和apply_async()方法時,第2個參數只能傳入元祖,傳入列表進程不會被執行,如下圖:
三、apply_async()方法callback參數的用法
示例:注意func2的入參是func1的返回值
_01(i):time.sleep(2)print('start_time:',time.ctime())returni+100deffun_02(arg):print('end_time:',arg,time.ctime())if__name__=='__main__':pool=Pool(3)foriinrange(4):pool.apply_async(func=fun_01,args=(i,),callback=fun_02)#fun_02的入參為fun_01的返回值#pool.apply_async(func=fun_01,args=(i,))pool.close()pool.join()print('done')map_async()方法callback參數的用法與apply_async()相同
四、使用進程池並關注結果
(msg):print('hello:',msg,time.ctime())time.sleep(2)print('end',time.ctime())return'done'+msgif__name__=='__main__':pool=multiprocessing.Pool(2)result=[]foriinrange(3):msg='hello%s'%iresult.append(pool.apply_async(func=func,args=(msg,)))pool.close()pool.join()forresinresult:print('***:',res.get())#get()函數得出每個返回結果的值print('Allend--')五、多進程執行多個函數
使用apply_async()或者apply()方法,可以實現多進程執行多個方法
示例:
():print(' RuntaskLee--%s******ppid:%s'%(os.getpid(),os.getppid()),'~~~~',time.ctime())start=time.time()time.sleep(5)end=time.time()print('TaskLee,runs%0.2fseconds.'%(end-start),'~~~~',time.ctime())defMarlon():print(" RuntaskMarlon-%s******ppid:%s"%(os.getpid(),os.getppid()),'~~~~',time.ctime())start=time.time()time.sleep(10)end=time.time()print('TaskMarlonruns%0.2fseconds.'%(end-start),'~~~~',time.ctime())defAllen():print(" RuntaskAllen-%s******ppid:%s"%(os.getpid(),os.getppid()),'~~~~',time.ctime())start=time.time()time.sleep(15)end=time.time()print('TaskAllenruns%0.2fseconds.'%(end-start),'~~~~',time.ctime())defFrank():print(" RuntaskFrank-%s******ppid:%s"%(os.getpid(),os.getppid()),'~~~~',time.ctime())start=time.time()time.sleep(20)end=time.time()print('TaskFrankruns%0.2fseconds.'%(end-start),'~~~~',time.ctime())if__name__=='__main__':func_list=[Lee,Marlon,Allen,Frank]print('parentprocessid%s'%os.getpid())pool=multiprocessing.Pool(4)forfuncinfunc_list:pool.apply_async(func)print('Waitingforallsubprocessesdone...')pool.close()pool.join()print('Allsubprocessesdone.')六、其他
1、獲取當前計算機的CPU數量
Ⅳ Python多進程multiprocessing模塊介紹
multiprocessing 是一個支持使用與 threading 模塊類似的 API 來產生進程的包。 multiprocessing 包同時提供了本地和遠程並發操作,通過使用子進程而非線程有效地繞過了 全局解釋器鎖。 因此,multiprocessing 模塊允許程序員充分利用給定機器上的多個處理器。 它在 Unix 和 Windows 上均可運行。
1、multiprocessing.Process(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)
2、相關方法
輸出結果如下:
Pool提供了一種快捷的方法,賦予函數並行化處理一系列輸入值的能力,可以將輸入數據分配給不同進程處理(數據並行)。下面的例子演示了在模塊中定義此類函數的常見做法,以便子進程可以成功導入該模塊。這個數據並行的基本例子使用了 Pool 。
將在標准輸出中列印
其中:
(1)p.apply(func [, args [, kwargs]]):在一個池工作進程中執行func( args, kwargs),然後返回結果。需要強調的是:此操作並不會在所有池工作進程中並執行func函數。如果要通過不同參數並發地執行func函數,必須從不同線程調用p.apply()函數或者使用p.apply_async()
(2)p.apply_async(func [, args [, kwargs]]):在一個池工作進程中執行func( args,**kwargs),然後返回結果。此方法的結果是 AsyncResult類的實例,callback是可調用對象,接收輸入參數。當func的結果變為可用時,將理解傳遞給callback。callback禁止執行任何阻塞操作,否則將接收其他非同步操作中的結果。多進程並發!
(3)p.close():關閉進程池,防止進一步操作。如果所有操作持續掛起,它們將在工作進程終止前完成
(4)p.jion():等待所有工作進程退出。此方法只能在close()或teminate()之後調用
Ⅳ python中的進程-實戰部分
如果想了解進程 可以先看一下這一篇 python中的進程-理論部分
python中的多線程無法利用多核優勢,如果想要充分地使用多核CPU的資源(os.cpu_count()查看),在python中大部分情況需要使用多進程。Python提供了multiprocessing。
multiprocessing模塊用來開啟子進程,並在子進程中執行我們定製的任務(比如函數),該模塊與多線程模塊threading的編程介面類似。
multiprocessing模塊的功能眾多:支持子進程、通信和共享數據、執行不同形式的同步,提供了Process、Queue、Pipe、Lock等組件。
需要再次強調的一點是:與線程不同,進程沒有任何共享狀態,進程修改的數據,改動僅限於該進程內。
創建進程的類 :
參數介紹:
group參數未使用,值始終為None
target表示調用對象,即子進程要執行的任務
args表示調用對象的位置參數元組,args=(1,2,'tiga',)
kwargs表示調用對象的字典,kwargs={'name':'tiga','age':18}
name為子進程的名稱
方法介紹:
p.start():啟動進程,並調用該子進程中的p.run()
p.run():進程啟動時運行的方法,正是它去調用target指定的函數,我們自定義類的類中一定要實現該方法
p.terminate():強制終止進程p,不會進行任何清理操作,如果p創建了子進程,該子進程就成了僵屍進程,使用該方法需要特別小心這種情況。如果p還保存了一個鎖那麼也將不會被釋放,進而導致死鎖
p.is_alive():如果p仍然運行,返回True
p.join([timeout]):主線程等待p終止(強調:是主線程處於等的狀態,而p是處於運行的狀態)。timeout是可選的超時時間,需要強調的是,p.join只能join住start開啟的進程,而不能join住run開啟的進程
屬性介紹:
注意:在windows中Process()必須放到# if __name__ == '__main__':下
創建並開啟子進程的兩種方式
方法一:
方法二:
有了join,程序不就是串列了嗎???
terminate與is_alive
name與pid