Python程序設(shè)計(jì)董付國(guó)(第二版)第13章多線程與多進(jìn)程編程_第1頁(yè)
Python程序設(shè)計(jì)董付國(guó)(第二版)第13章多線程與多進(jìn)程編程_第2頁(yè)
Python程序設(shè)計(jì)董付國(guó)(第二版)第13章多線程與多進(jìn)程編程_第3頁(yè)
Python程序設(shè)計(jì)董付國(guó)(第二版)第13章多線程與多進(jìn)程編程_第4頁(yè)
Python程序設(shè)計(jì)董付國(guó)(第二版)第13章多線程與多進(jìn)程編程_第5頁(yè)
已閱讀5頁(yè),還剩60頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第13章多線程與多進(jìn)程編程多線程與多進(jìn)程編程

常見(jiàn)的多線程技術(shù)應(yīng)用場(chǎng)景:在執(zhí)行一段代碼的同時(shí)還可以接收和響應(yīng)用戶的鍵盤或鼠標(biāo)事件以提高用戶體驗(yàn);Windows操作系統(tǒng)的WindowsIndexingServices創(chuàng)建了一個(gè)低優(yōu)先級(jí)的線程,該線程定期被喚醒并對(duì)磁盤上的特定區(qū)域的文件內(nèi)容進(jìn)行索引以提高用戶搜索速度;打開(kāi)Photoshop、3DsMax這樣的大型軟件時(shí)需要加載很多模塊和動(dòng)態(tài)鏈接庫(kù),軟件啟動(dòng)時(shí)間會(huì)比較長(zhǎng),可以使用一個(gè)線程來(lái)顯示一個(gè)小動(dòng)畫(huà)來(lái)表示當(dāng)前軟件正在啟動(dòng),當(dāng)后臺(tái)線程加載完所有的模塊和庫(kù)之后,結(jié)束該動(dòng)畫(huà)的播放并打開(kāi)軟件主界面;字處理軟件可以使用一個(gè)優(yōu)先級(jí)高的線程來(lái)接收用戶鍵盤輸入,而使用一些低優(yōu)先級(jí)線程來(lái)進(jìn)行拼寫(xiě)檢查、語(yǔ)法檢查、分頁(yè)以及字?jǐn)?shù)統(tǒng)計(jì)之類的功能并將結(jié)果顯示在狀態(tài)欄上,對(duì)于提高用戶體驗(yàn)有重要幫助。

多線程與多進(jìn)程編程

在多核、多處理器平臺(tái)上,在任意時(shí)刻每個(gè)核可以運(yùn)行一個(gè)線程,多個(gè)線程同時(shí)運(yùn)行并相互協(xié)作,從而達(dá)到高速處理任務(wù)的目的。

即使是高端服務(wù)器或工作站甚至集群系統(tǒng),處理器和核的數(shù)量總是有限的,如果線程的數(shù)量多于核的數(shù)量,就必然需要進(jìn)行調(diào)度。

在調(diào)度時(shí),處理器為每個(gè)線程分配一個(gè)很短的時(shí)間片,所有線程根據(jù)具體的調(diào)度算法輪流獲得該時(shí)間片。當(dāng)時(shí)間片用完以后,即使該線程還沒(méi)有執(zhí)行完也要退出處理器并等待下次調(diào)度,同時(shí)由操作系統(tǒng)按照優(yōu)先級(jí)再選擇一個(gè)線程進(jìn)入CPU運(yùn)行。多線程與多進(jìn)程編程

對(duì)于單核單CPU而言,使用多線程并不能提高任務(wù)處理速度,但有些場(chǎng)合必須使用多線程技術(shù),例如GUI界面的用戶體驗(yàn)。

并不是使用的線程數(shù)量越多越好,如果線程太多的話,線程調(diào)度帶來(lái)的開(kāi)銷可能會(huì)比線程實(shí)際執(zhí)行的開(kāi)銷還大,這樣使用多線程就失去本來(lái)的意義了。多線程與多進(jìn)程編程

系統(tǒng)運(yùn)行過(guò)程中存在大量的線程。多線程與多進(jìn)程編程

大多數(shù)線程要經(jīng)過(guò)很多次調(diào)度才能完成預(yù)定的任務(wù)。多線程與多進(jìn)程編程

Python多線程編程技術(shù)存在GIL問(wèn)題,而使用多進(jìn)程則有效地避免了這個(gè)問(wèn)題,進(jìn)一步提高了系統(tǒng)吞吐量。13.1threading模塊方法功能說(shuō)明active_count()、activeCount()current_thread()、currentThread()threading.get_ident()返回當(dāng)前處于alive狀態(tài)的Thread對(duì)象數(shù)量返回當(dāng)前Thread對(duì)象返回當(dāng)前線程的線程標(biāo)識(shí)符。線程標(biāo)識(shí)符是一個(gè)非負(fù)整數(shù),并沒(méi)特殊含義,只是用來(lái)標(biāo)識(shí)線程,該整數(shù)可能會(huì)被循環(huán)利用。Python3.3及以后版本支持該方法返回當(dāng)前處于alive狀態(tài)的所有Thread對(duì)象列表返回主線程對(duì)象,即啟動(dòng)Python解釋器的線程對(duì)象。Python3.4及以后版本支持該方法threading.enumerate()threading.main_thread()threading.stack_size([size返回創(chuàng)建線程時(shí)使用的棧的大小,如果指定size參數(shù),])則用來(lái)指定后續(xù)創(chuàng)建的線程使用的棧大小,size必須是0(表示使用系統(tǒng)默認(rèn)值)或大于32K的正整數(shù)線程類,用于創(chuàng)建和管理線程事件類,用于線程同步條件類,用于線程同步鎖類,用于線程同步信號(hào)量類,用于線程同步用于在指定時(shí)間之后調(diào)用一個(gè)函數(shù)的情況ThreadEventConditionLock、RLockSemaphoreTimer13.1threading模塊>>>importthreading>>>threading.stack_size()#查看當(dāng)前線程棧的大小0>>>threading.stack_size(64*1024)#設(shè)置當(dāng)前線程棧的大小0>>>threading.stack_size()65536>>>threading.active_count()#查看活動(dòng)線程數(shù)量213.1threading模塊>>>threading.current_thread()#返回當(dāng)前線程對(duì)象<_MainThread(MainThread,started4852)>>>>threading.enumerate()#枚舉所有線程[<Thread(SockThread,starteddaemon9620)>,<_MainThread(MainThread,started4852)>]>>>defdemo(v):print(v)>>>t=threading.Timer(3,demo,args=(5,))#創(chuàng)建線程>>>t.start()#啟動(dòng)線程,3秒之后調(diào)用demo函數(shù)>>>t.cancel()#如果仍在等待時(shí)間到達(dá),則取消13.2Thread對(duì)象

可以通過(guò)為Thread類的構(gòu)造函數(shù)傳遞一個(gè)可調(diào)用對(duì)象來(lái)創(chuàng)建線程。

可以繼承threading.Thread類創(chuàng)建派生類,并重寫(xiě)__init__和run方法,實(shí)現(xiàn)自定義線程對(duì)象類。創(chuàng)建了線程對(duì)象以后,可以調(diào)用其start()方法來(lái)啟動(dòng),該方法自動(dòng)調(diào)用該類對(duì)象的run方法,此時(shí)該線程處于alive狀態(tài),直至run方法結(jié)束。13.2Thread對(duì)象

通過(guò)繼承Thread類創(chuàng)建線程類importthreadingclassmythread(threading.Thread):def__init__(self,num):threading.Thread.__init__(self)self.num=numdefrun(self):#線程運(yùn)行的主要代碼print('Iam{0}'.format(self.num))t1=mythread(1)#創(chuàng)建線程t2=mythread(2)t3=mythread(3)t1.start()#啟動(dòng)線程t2.start()t3.start()13.2Thread對(duì)象

Thread對(duì)象成員成員說(shuō)明start()run()自動(dòng)調(diào)用run()方法,啟動(dòng)線程,執(zhí)行線程代碼線程代碼,用來(lái)實(shí)現(xiàn)線程的功能與業(yè)務(wù)邏輯,可以在子類中重寫(xiě)該方法來(lái)自定義線程的行為構(gòu)造函數(shù)__init__(self,group=None,target=None,name=None,args=(),kwargs=None,verbose=None)nameidentis_alive()、isAlive()daemonjoin(timeout=None)用來(lái)讀取或設(shè)置線程的名字線程標(biāo)識(shí),非0數(shù)字或None(線程未被啟動(dòng))測(cè)試線程是否處于alive狀態(tài)布爾值,表示線程是否為守護(hù)線程等待線程結(jié)束或超時(shí)返回13.2.1Thread對(duì)象中的方法

join([timeout]:等待被調(diào)線程結(jié)束后再繼續(xù)執(zhí)行后續(xù)代碼,timeout為最長(zhǎng)等待時(shí)間,單位為秒。例13-1使用Thread類的構(gòu)造方法創(chuàng)建線程。importthreadingimporttimedeffunc1(x,y):#線程函數(shù)foriinrange(x,y):print(i)time.sleep(10)t1=threading.Thread(target=func1,args=(15,20))t1.start()t1.join(5)t2=threading.Thread(target=func1,args=(5,10))t2.start()13.2.1Thread對(duì)象中的方法

例13-2查看線程狀態(tài)。importthreadingimporttimedeffunc1(x,y):isAlive():測(cè)試線程是否處于運(yùn)行狀態(tài)foriinrange(x,y):print(i)t1=threading.Thread(target=func1,args=(15,20))t1.start()t1.join(5)#注釋掉這里試試t2=threading.Thread(target=func1,args=(5,10))t2.start()t2.join()#注釋掉這里試試print(t1.isAlive())print(t2.isAlive())13.2.2Thread對(duì)象中的daemon屬性

在腳本運(yùn)行過(guò)程中有一個(gè)主線程,若在主線程中創(chuàng)建了子線程,則:

當(dāng)子線程的daemon屬性為False時(shí),主線程結(jié)束時(shí)會(huì)檢測(cè)子線程是否結(jié)束,如果子線程尚未完成,則主線程會(huì)等待子線程完成后再退出;

當(dāng)子線程的daemon屬性為True時(shí),主線程運(yùn)行結(jié)束時(shí)不對(duì)子線程進(jìn)行檢查而直接退出,同時(shí)子線程將隨主線程一起結(jié)束,而不論是否運(yùn)行完成。以上論述不適用于IDLE中的交互模式或腳本運(yùn)行模式,因?yàn)樵诮换ツJ较碌闹骶€程只有在退出Python時(shí)才終止。

13.2.2Thread對(duì)象中的daemon屬性

例13-3線程的daemon屬性。importthreadingimporttimeclassmythread(threading.Thread):def__init__(self,num,threadname):threading.Thread.__init__(self,name=threadname)self.num=numdefrun(self):time.sleep(self.num)#阻塞線程self.num秒print(self.num)t1=mythread(1,'t1')t2=mythread(5,'t2')t2.daemon=Trueprint(t1.daemon)print(t2.daemon)t1.start()t2.start()13.2.2Thread對(duì)象中的daemon屬性

在IDLE中的運(yùn)行結(jié)果13.2.2Thread對(duì)象中的daemon屬性

在cmd中的運(yùn)行結(jié)果13.2.2Thread對(duì)象中的daemon屬性

例13-4調(diào)用線程對(duì)象的普通方法。線程類首先也是一個(gè)普通類,同時(shí)還具有線程類特有的一些方法。13.2.2Thread對(duì)象中的daemon屬性importthreadingimporttimeclassmyThread(threading.Thread):def__init__(self,threadName):threading.Thread.__init__(self)=threadNamedefrun(self):#線程運(yùn)行的核心代碼time.sleep(1)print('Inrun:',)defoutput(self):#在線程類中定義普通方法print('Inoutput:',)13.2.2Thread對(duì)象中的daemon屬性t=myThread('test')t.start()#啟動(dòng)線程t.output()#調(diào)用普通方法time.sleep(2)print('OK')13.3線程同步技術(shù)

將任務(wù)拆分成互相協(xié)作的多個(gè)線程同時(shí)運(yùn)行,那么屬于同一個(gè)任務(wù)的多個(gè)線程之間必然會(huì)有交互和同步以便互相協(xié)作地完成任務(wù)。多線程同步時(shí)如果需要獲得多個(gè)鎖才能進(jìn)入臨界區(qū)的話,可能會(huì)發(fā)生死鎖,在多線程編程時(shí)一定要注意并認(rèn)真檢查和避免這種情況。13.3.1Lock/RLock對(duì)象

Lock是比較低級(jí)的同步原語(yǔ),當(dāng)被鎖定以后不屬于特定的線程。

一個(gè)鎖有兩種狀態(tài):locked和unlocked。如果鎖處于unclocked狀態(tài),acquire()方法將其修改為locked并立即返回;如果鎖已處于locked狀態(tài),則阻塞當(dāng)前線程并等待其他線程釋放鎖,然后將其修改為locked并立即返回。

release()方法將鎖狀態(tài)由locked修改為unlocked并立即返回,如果鎖狀態(tài)本來(lái)已經(jīng)是unlocked,調(diào)用該方法將會(huì)拋出異常。13.3.1Lock/RLock對(duì)象

可重入鎖RLock對(duì)象也是一種常用的線程同步原語(yǔ),可被同一個(gè)線程acquire多次。

當(dāng)處于locked狀態(tài)時(shí),某線程擁有該鎖;當(dāng)處于unlocked狀態(tài)時(shí),該鎖不屬于任何線程。

RLock對(duì)象的acquire()/release()調(diào)用對(duì)可以嵌套,僅當(dāng)最后一個(gè)或者最外層的release()執(zhí)行結(jié)束,鎖被設(shè)置為unlocked狀態(tài)。13.3.1Lock/RLock對(duì)象

例13-5使用Lock/RLock對(duì)象實(shí)現(xiàn)線程同步。importthreadingimporttimeclassmythread(threading.Thread):def__init__(self):threading.Thread.__init__(self)defrun(self):globalx#聲明全局變量lock.acquire()#獲取鎖,進(jìn)入臨界區(qū)foriinrange(3):x=x+itime.sleep(2)print(x)lock.release()#釋放鎖,退出臨界區(qū)13.3.1Lock/RLock對(duì)象lock=threading.Lock()#創(chuàng)建鎖,這里也可以使用RLocktl=[]foriinrange(10):#創(chuàng)建10個(gè)線程t=mythread()tl.append(t)x=0foriintl:#啟動(dòng)10個(gè)線程i.start()13.3.2Condition對(duì)象

使用Condition對(duì)象可以在某些事件觸發(fā)后才處理數(shù)據(jù)或執(zhí)行特定的功能代碼,可以用于不同線程之間的通信或通知,以實(shí)現(xiàn)更高級(jí)別的同步。

Condition對(duì)象除了具有acquire()和release()方法之外,還有wait()、notify()、notify_all()等方法。13.3.2Condition對(duì)象

例13-6使用Condition對(duì)象實(shí)現(xiàn)線程同步。

使用Condition對(duì)象可以在某些事件觸發(fā)后才處理數(shù)據(jù)。

Condition對(duì)象除了具有acquire和release方法之外,還有wait、notify、notify_all等方法。13.3.2Condition對(duì)象生產(chǎn)者類importthreadingclassProducer(threading.Thread):def__init__(self,threadname):threading.Thread.__init__(self,name=threadname)defrun(self):globalxcon.acquire()ifx==20:con.wait()else:print('\nProducer:',end='')foriinrange(20):print(x,end='')x=x+1print(x)con.notify()con.release()13.3.2Condition對(duì)象消費(fèi)者類classConsumer(threading.Thread):def__init__(self,threadname):threading.Thread.__init__(self,name=threadname)defrun(self):globalxcon.acquire()ifx==0:con.wait()else:print('\nConsumer:',end='')foriinrange(20):print(x,end='')x=x-1print(x)con.notify()con.release()13.3.2Condition對(duì)象創(chuàng)建Condition對(duì)象以及生產(chǎn)者與消費(fèi)者線程con=threading.Condition()x=0p=Producer('Producer')c=Consumer('Consumer')p.start()c.start()p.join()c.join()print('\nAfterProducerandConsumeralldone:',x)13.3.2Condition對(duì)象?運(yùn)行結(jié)果13.3.3Queue對(duì)象

queue模塊(在Python2中為Queue模塊)的Queue對(duì)象實(shí)現(xiàn)了多生產(chǎn)者/多消費(fèi)者隊(duì)列,尤其適合需要在多個(gè)線程之間進(jìn)行信息交換的場(chǎng)合,實(shí)現(xiàn)了多線程編程所需要的所有鎖語(yǔ)義。13.3.3Queue對(duì)象

使用Queue對(duì)象實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者線程同步importthreadingimporttimefromqueueimportQueueclassProducer(threading.Thread):def__init__(self,threadname):threading.Thread.__init__(self,name=threadname)defrun(self):globalmyqueuemyqueue.put(self.getName())print(self.getName(),'put',self.getName(),'toqueue.')13.3.3Queue對(duì)象classConsumer(threading.Thread):def__init__(self,threadname):threading.Thread.__init__(self,name=threadname)defrun(self):globalmyqueueprint(self.getName(),'get',myqueue.get(),'fromqueue.')13.3.3Queue對(duì)象myqueue=Queue()plist=[]clist=[]foriinrange(10):p=Producer('Producer'+str(i))plist.append(p)c=Consumer('Consumer'+str(i))clist.append(c)foriinplist:i.start()i.join()foriinclist:i.start()i.join()13.3.3Queue對(duì)象

補(bǔ)充案例:使用Queue類實(shí)現(xiàn)多線程復(fù)制文件,利用該類提供的機(jī)制來(lái)保證多個(gè)線程的同步。code\multiThread_copyFile.py使用方法:C:\Python35>pythonmultiThread_copyFile.py-husage:multiThread_copyFile.py[-h][-sSRC][-dDST][-nNUM]copyfilesfromsrctodstoptionalarguments:-h,--helpshowthishelpmessageandexit-sSRC,--srcSRC-dDST,--dstDST-nNUM,--numNUM13.3.4Event對(duì)象

Event對(duì)象的set()方法可以設(shè)置Event對(duì)象內(nèi)部的信號(hào)標(biāo)志為真;Event對(duì)象的clear()方法可以清除Event對(duì)象內(nèi)部的信號(hào)標(biāo)志,將其設(shè)置為假;Event對(duì)象的isSet()方法用來(lái)判斷其內(nèi)部信號(hào)標(biāo)志的狀態(tài);Event對(duì)象的wait()方法只有在其內(nèi)部信號(hào)狀態(tài)為真時(shí)將很快地執(zhí)行并返回;若Event對(duì)象的內(nèi)部信號(hào)標(biāo)志為假,wait方法將一直等待至超時(shí)或內(nèi)部信號(hào)狀態(tài)為真。

13.3.4Event對(duì)象

例13-7使用Event對(duì)象實(shí)現(xiàn)線程同步。importthreadingclassmythread(threading.Thread):def__init__(self,threadname):threading.Thread.__init__(self,name=threadname)defrun(self):globalmyeventifmyevent.isSet():myevent.clear()myevent.wait()print(self.getName())else:print(self.getName())myevent.set()13.3.4Event對(duì)象myevent=threading.Event()myevent.set()tl=[]foriinrange(10):t=mythread(str(i))tl.append(t)foriintl:i.start()13.3.4Event對(duì)象

每次運(yùn)行結(jié)果可能會(huì)不同,其中一次是13.3.5Semaphore與BoundedSemaphore(擴(kuò)展)

Semaphore對(duì)象維護(hù)著一個(gè)內(nèi)部計(jì)數(shù)器,調(diào)用acquire()方法時(shí)該計(jì)數(shù)器減1,調(diào)用release()方法時(shí)該計(jì)數(shù)器加1,適用于需要控制特定資源的并發(fā)訪問(wèn)線程數(shù)量的場(chǎng)合。調(diào)用acquire()方式時(shí),如果計(jì)數(shù)器已經(jīng)為0則阻塞當(dāng)前線程直到有其他線程調(diào)用了release()方法,所以計(jì)數(shù)器的值永遠(yuǎn)不會(huì)小于0。Semaphore對(duì)象可以調(diào)用任意次release()方法,而B(niǎo)oundedSemaphore對(duì)象可以保證計(jì)數(shù)器的值不超過(guò)特定的值。13.3.5Semaphore與BoundedSemaphore(擴(kuò)展)

補(bǔ)充案例:使用BoundedSemaphore對(duì)象限制特定資源的并發(fā)訪問(wèn)線程數(shù)量。importthreadingimporttimedefworker(value):withsema:print(value)time.sleep(8)#同一時(shí)刻最多允許2個(gè)線程訪問(wèn)特定資源sema=threading.BoundedSemaphore(2)foriinrange(10):t=threading.Thread(target=worker,args=(i,))t.start()13.3.6Barrier對(duì)象(擴(kuò)展)

Barrier對(duì)象常用來(lái)實(shí)現(xiàn)這樣的線程同步,多個(gè)線程運(yùn)行到某個(gè)時(shí)間點(diǎn)以后每個(gè)線程都需要等著其他線程都準(zhǔn)備好以后再同時(shí)進(jìn)行下一步工作。類似于賽馬時(shí)需要先用柵欄攔住,每個(gè)試圖穿過(guò)柵欄的選手都需要明確說(shuō)明自己準(zhǔn)備好了,當(dāng)所有選手都表示準(zhǔn)備好以后,柵欄打開(kāi),所有選手同時(shí)沖出柵欄。13.3.6Barrier對(duì)象(擴(kuò)展)

補(bǔ)充案例:創(chuàng)建了一個(gè)允許3個(gè)線程互相等待的Barrier對(duì)象,每個(gè)線程做完一些準(zhǔn)備工作后調(diào)用Barrier對(duì)象的wait()方法等待其他線程,當(dāng)所有線程都調(diào)用了wait()方法之后,會(huì)調(diào)用指定的action對(duì)象,然后同時(shí)開(kāi)始執(zhí)行wait()之后的代碼。13.3.6Barrier對(duì)象(擴(kuò)展)importthreadingimportrandomimporttimedefworker(arg):#假設(shè)每個(gè)線程需要不同的時(shí)間來(lái)完成準(zhǔn)備工作time.sleep(random.randint(1,20))#假設(shè)已知任何線程的準(zhǔn)備工作最多需要20秒#每個(gè)線程調(diào)用wait()時(shí),返回值不一樣r=b.wait(20)ifr==0:print(arg)13.3.6Barrier對(duì)象(擴(kuò)展)defprintOk():print('ok')#允許3個(gè)線程等待#如果線程調(diào)用wait()時(shí)沒(méi)有指定超時(shí)時(shí)間,默認(rèn)為20秒b=threading.Barrier(parties=3,action=printOk,timeout=20)#創(chuàng)建并啟動(dòng)3個(gè)線程,線程數(shù)量必須與Barrier對(duì)象的parties一致foriinrange(3):t=threading.Thread(target=worker,args=(i,))t.start()13.4多進(jìn)程編程

進(jìn)程是正在執(zhí)行中的應(yīng)用程序。一個(gè)進(jìn)程是一個(gè)執(zhí)行中的文件使用資源的總和,包括虛擬地址空間、代碼、數(shù)據(jù)、對(duì)象句柄、環(huán)境變量和執(zhí)行單元等等。一個(gè)應(yīng)用程序同時(shí)打開(kāi)并執(zhí)行多次,就會(huì)創(chuàng)建多個(gè)進(jìn)程。

Python標(biāo)準(zhǔn)庫(kù)multiprocessing支持使用類似于threading的用法來(lái)創(chuàng)建與管理進(jìn)程,并且避免了GIL(GlobalInterpreterLock)問(wèn)題,可以更有效地利用CPU資源。13.4.1創(chuàng)建進(jìn)程

通過(guò)創(chuàng)建Process對(duì)象來(lái)創(chuàng)建進(jìn)程,通過(guò)start()方法啟動(dòng)。frommultiprocessingimportProcessimportosdeff(name):print(':',__name__)print('cess:',os.getppid())#查看父進(jìn)程IDprint('processid:',os.getpid())#查看當(dāng)前進(jìn)程IDprint('hello',name)if__name__=='__main__':p=Process(target=f,args=('bob',))#創(chuàng)建進(jìn)程p.start()#啟動(dòng)進(jìn)程p.join()#等待進(jìn)程結(jié)束13.4.1創(chuàng)建進(jìn)程

使用Pool對(duì)象進(jìn)行數(shù)據(jù)并行處理。frommultiprocessingimportPoolfromstatisticsimportmeandeff(x):returnmean(x)if__name__=='__main__':x=[list(range(10)),list(range(20,30)),list(range(50,60)),list(range(80,90))]withPool(5)asp:print(p.map(f,x))13.4.2進(jìn)程間數(shù)據(jù)交換

例13-8使用Queue對(duì)象在進(jìn)程間交換數(shù)據(jù)。importmultiprocessingasmpdeffoo(q):q.put('helloworld!')if__name__=='__main__':mp.set_start_method('spawn')#Windows系統(tǒng)創(chuàng)建子進(jìn)程的默認(rèn)方式q=mp.Queue()p=mp.Process(target=foo,args=(q,))p.start()p.join()print(q.get())13.4.2進(jìn)程間數(shù)據(jù)交換

也可以使用上下文對(duì)象context的Queue對(duì)象實(shí)現(xiàn)進(jìn)程間的數(shù)據(jù)交換。importmultiprocessingasmpdeffoo(q):q.put('helloworld')if__name__=='__main__':ctx=mp.get_context('spawn')q=ctx.Queue()p=ctx.Process(target=foo,args=(q,))p.start()p.join()print(q.get())13.4.2進(jìn)程間數(shù)據(jù)交換

例13-9使用管道實(shí)現(xiàn)進(jìn)程間數(shù)據(jù)交換。frommultiprocessingimportProcess,Pipedeff(conn):conn.send('helloworld')#向管道中發(fā)送數(shù)據(jù)conn.close()if__name__=='__main__':parent_conn,child_conn=Pipe()#創(chuàng)建管道對(duì)象p=Process(target=f,args=(child_conn,))#將管道的一方傳遞給子進(jìn)程p.start()print(parent_conn.recv())#通過(guò)管道的另一方獲取數(shù)據(jù)p.join()13.4.2進(jìn)程間數(shù)據(jù)交換

例13-10使用共享內(nèi)存實(shí)現(xiàn)進(jìn)程間數(shù)據(jù)交換,比較適合大量數(shù)據(jù)的場(chǎng)合。frommultiprocessingimportProcess,Value,Arraydeff(n,a):n.value=3.1415927foriinrange(len(a)):a[i]=a[i]*a[i]if__name__=='__main__':num=Value('d',0.0)#實(shí)型arr=Array('i',range(10))#整型數(shù)組p=Process(target=f,args=(num,arr))p.start()p.join()print(num.value)print(arr[:])13.4.2進(jìn)程間數(shù)據(jù)交換

例13-11Manager對(duì)象控制一個(gè)擁有l(wèi)ist、dict、Lock、RLock、Semaphore、BoundedSemaphore、Condition、Event、Barrier、Queue、Value、Array、Namespace等對(duì)象的服務(wù)端進(jìn)程,并且允許其他進(jìn)程訪問(wèn)這些對(duì)象。使用Manager對(duì)象實(shí)現(xiàn)進(jìn)程間數(shù)據(jù)交換。13.4.2進(jìn)程間數(shù)據(jù)交換frommultiprocessingimportProcess,Managerdeff(d,l,t):d['name']='DongFuguo'd['age']=38d['sex']='Male'd['affiliation']='SDIBT'l.reverse()t.value=313.4.2進(jìn)程間數(shù)據(jù)交換if__name__=='__main__':withManager()asmanager:d=manager.dict()l=manager.list(range(10))t=manager.Value('i',0)p=Process(target=f,args=(d,l,t))p.start()p.join()foritemind.items():print(item)print(l)print(t.value)13.4.2進(jìn)程間數(shù)據(jù)交換?補(bǔ)充案例:使用Manager對(duì)象實(shí)現(xiàn)不同機(jī)器上的進(jìn)程跨網(wǎng)絡(luò)共享數(shù)據(jù)。13.4.2進(jìn)程間數(shù)據(jù)交換(1)首先編寫(xiě)程序文件multiprocessing_server.py,啟動(dòng)服務(wù)器進(jìn)程,創(chuàng)建可共享的隊(duì)列對(duì)象。frommultiprocessing.managersimportBaseManagerfromqueueimportQueueq=Queue()classQueueManager(BaseManager):passQueueManager.register('get_queue',callable=lambda:q)m=QueueManager(address=('',30030),authkey=b'dongfuguo')s=m.get_server()s.serve_forever()13.4.2進(jìn)程間數(shù)據(jù)交換(2)然后編寫(xiě)程序

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論