并發(fā)編程2尚學(xué)堂百戰(zhàn)程序員-python-進(jìn)程和多線程_第1頁(yè)
并發(fā)編程2尚學(xué)堂百戰(zhàn)程序員-python-進(jìn)程和多線程_第2頁(yè)
并發(fā)編程2尚學(xué)堂百戰(zhàn)程序員-python-進(jìn)程和多線程_第3頁(yè)
并發(fā)編程2尚學(xué)堂百戰(zhàn)程序員-python-進(jìn)程和多線程_第4頁(yè)
并發(fā)編程2尚學(xué)堂百戰(zhàn)程序員-python-進(jìn)程和多線程_第5頁(yè)
已閱讀5頁(yè),還剩49頁(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)介

python-多進(jìn)程和多線程講師:尚玉杰CONTENTSLoremipsumdolorsitamet,consecteturadipiscingelit.Donecluctusnibhsitametsemvulputatevenenatisbibendumorcipulvinar.01.多任務(wù)Loremipsumdolorsitamet,consecteturadipiscingelit02.多進(jìn)程Loremipsumdolorsitamet,consecteturadipiscingelit03.多線程Loremipsumdolorsitamet,consecteturadipiscingelit04.線程同步Loremipsumdolorsitamet,consecteturadipiscingelit01多任務(wù)PARTONE多任務(wù)處理多任務(wù)處理:使得計(jì)算機(jī)可以同時(shí)處理多個(gè)任務(wù)聽(tīng)歌的同時(shí)QQ聊天、辦公、下載文件實(shí)現(xiàn)方式:多進(jìn)程、多線程

CPUQQ飛秋網(wǎng)易音樂(lè)word微信并發(fā)并行02多進(jìn)程PARTTWO多進(jìn)程程序:是一個(gè)指令的集合進(jìn)程:正在執(zhí)行的程序;或者說(shuō):當(dāng)你運(yùn)行一個(gè)程序,你就啟動(dòng)了一個(gè)進(jìn)程編寫完的代碼,沒(méi)有運(yùn)行時(shí),稱為程序,正在運(yùn)行的代碼,稱為進(jìn)程程序是死的(靜態(tài)的),進(jìn)程是活的(動(dòng)態(tài)的)操作系統(tǒng)輪流讓各個(gè)任務(wù)交替執(zhí)?,由于CPU的執(zhí)?速度實(shí)在是太快了,我們感覺(jué)就像所有任務(wù)都在同時(shí)執(zhí)??樣

多進(jìn)程中,每個(gè)進(jìn)程中所有數(shù)據(jù)(包括全局變量)都各自擁有?份,互

不影響

多進(jìn)程模擬多任務(wù)處理:一邊唱歌一邊跳舞fromtimeimportsleepdefsing():foriinrange(3):print("正在唱歌")dance()sleep(1)defdance():print("正在跳舞")if__name__=='__main__':sing()

多進(jìn)程程序開(kāi)始運(yùn)行時(shí),首先會(huì)創(chuàng)建一個(gè)主進(jìn)程在主進(jìn)程(父進(jìn)程)下,我們可以創(chuàng)建新的進(jìn)程(子進(jìn)程),子進(jìn)程依賴于主進(jìn)程,如果主進(jìn)程結(jié)束,程序會(huì)退出Python提供了非常好用的多進(jìn)程包multiprocessing,借助這個(gè)包,可以輕松完成從單進(jìn)程到并發(fā)執(zhí)行的轉(zhuǎn)換

多進(jìn)程multiprocessing模塊提供了?個(gè)Process類來(lái)創(chuàng)建?個(gè)進(jìn)程對(duì)象frommultiprocessingimportProcessdefrun(name):print("子進(jìn)程運(yùn)行中,name=%s"%(name))if__name__=="__main__":print("父進(jìn)程啟動(dòng)")p=Process(target=run,args=('test',))#target表示調(diào)用對(duì)象,args表示調(diào)用對(duì)象的位置參數(shù)元組#(注意:元組中只有一個(gè)元素時(shí)結(jié)尾要加,)

print("子進(jìn)程將要執(zhí)行")p.start()print()#p.pidp.join()print("子進(jìn)程結(jié)束")

多進(jìn)程if__name__==“__main__”:說(shuō)明一個(gè)python的文件有兩種使用的方法,第一是直接作為程序執(zhí)行,第二是import到其他的python程序中被調(diào)用(模塊重用)執(zhí)行。因此if__name__=='main':的作用就是控制這兩種情況執(zhí)行代碼的過(guò)程,__name__是內(nèi)置變量,用于表示當(dāng)前模塊的名字在if__name__=='main':下的代碼只有在文件作為程序直接執(zhí)行才會(huì)被執(zhí)行,而import到其他程序中是不會(huì)被執(zhí)行的在Windows上,子進(jìn)程會(huì)自動(dòng)import啟動(dòng)它的這個(gè)文件,而在import的時(shí)候是會(huì)執(zhí)行這些語(yǔ)句的。如果不加if__name__=="__main__":的話就會(huì)無(wú)限遞歸創(chuàng)建子進(jìn)程所以必須把創(chuàng)建子進(jìn)程的部分用那個(gè)if判斷保護(hù)起來(lái)import的時(shí)候__name__不是__main__,就不會(huì)遞歸運(yùn)行了

多進(jìn)程Process(target,name,args)參數(shù)介紹target表示調(diào)用對(duì)象,即子進(jìn)程要執(zhí)行的任務(wù)args表示調(diào)用對(duì)象的位置參數(shù)元組,args=(1,)name為子進(jìn)程的名稱多進(jìn)程Process類常??法:p.start():?jiǎn)?dòng)進(jìn)程,并調(diào)用該子進(jìn)程中的p.run()p.run():進(jìn)程啟動(dòng)時(shí)運(yùn)行的方法,正是它去調(diào)用target指定的函數(shù),我們自定義類的類中一定要實(shí)現(xiàn)該方法p.terminate()(了解)強(qiáng)制終止進(jìn)程p,不會(huì)進(jìn)行任何清理操作p.is_alive():如果p仍然運(yùn)行,返回True.用來(lái)判斷進(jìn)程是否還在運(yùn)行p.join([timeout]):主進(jìn)程等待p終止,timeout是可選的超時(shí)時(shí)間多進(jìn)程Process類常?屬性:

name:當(dāng)前進(jìn)程實(shí)例別名,默認(rèn)為Process-N,N為從1開(kāi)始遞增的整

數(shù);

pid:當(dāng)前進(jìn)程實(shí)例的PID值

多進(jìn)程全局變量在多個(gè)進(jìn)程中不共享:進(jìn)程之間的數(shù)據(jù)是獨(dú)立的,默認(rèn)情況下互不影響

frommultiprocessingimportProcessnum=1defrun1():globalnumnum+=5print("子進(jìn)程1運(yùn)行中,num=%d"%(num))defrun2():globalnumnum+=10print("子進(jìn)程2運(yùn)行中,num=%d"%(num))if__name__=="__main__":print("父進(jìn)程啟動(dòng)")p1=Process(target=run1)p2=Process(target=run2)print("子進(jìn)程將要執(zhí)行")p1.start()p2.start()p1.join()p2.join()print("子進(jìn)程結(jié)束")多進(jìn)程創(chuàng)建新的進(jìn)程還能夠使?類的?式,可以?定義?個(gè)類,繼承Process類,每次實(shí)例化這個(gè)類的時(shí)候,就等同于實(shí)例化?個(gè)進(jìn)程對(duì)象importmultiprocessingimporttimeclassClockProcess(multiprocessing.Process):defrun(self):n=5whilen>0:print(n)time.sleep(1)n-=1if__name__=='__main__':p=ClockProcess()p.start()p.join()

進(jìn)程池進(jìn)程池:用來(lái)創(chuàng)建多個(gè)進(jìn)程當(dāng)需要?jiǎng)?chuàng)建的?進(jìn)程數(shù)量不多時(shí),可以直接利?multiprocessing中的Process動(dòng)態(tài)生成多個(gè)進(jìn)程,但如果是上百甚?上千個(gè)?標(biāo),?動(dòng)的去創(chuàng)建進(jìn)程的?作量巨?,此時(shí)就可以?到multiprocessing模塊提供的Pool初始化Pool時(shí),可以指定?個(gè)最?進(jìn)程數(shù),當(dāng)有新的請(qǐng)求提交到Pool中時(shí),

如果池還沒(méi)有滿,那么就會(huì)創(chuàng)建?個(gè)新的進(jìn)程?來(lái)執(zhí)?該請(qǐng)求;但如果池中

的進(jìn)程數(shù)已經(jīng)達(dá)到指定的最?值,那么該請(qǐng)求就會(huì)等待,直到池中有進(jìn)程結(jié)

束,才會(huì)創(chuàng)建新的進(jìn)程來(lái)執(zhí)?進(jìn)程池frommultiprocessingimportPoolimportrandom,timedefwork(num):print(random.random()*num)time.sleep(3)if__name__=="__main__":po=Pool(3)#定義一個(gè)進(jìn)程池,最大進(jìn)程數(shù)為3,默認(rèn)大小為CPU核數(shù)foriinrange(10):po.apply_async(work,(i,))#apply_async選擇要調(diào)用的目標(biāo),每次循環(huán)會(huì)用空出來(lái)的子進(jìn)程去調(diào)用目標(biāo)

po.close()#進(jìn)程池關(guān)閉之后不再接收新的請(qǐng)求

po.join()#等待po中所有子進(jìn)程結(jié)束,必須放在close后面在多進(jìn)程中:主進(jìn)程一般用來(lái)等待,真正的任務(wù)都在子進(jìn)程中執(zhí)行

進(jìn)程池multiprocessing.Pool常?函數(shù)解析:apply_async(func[,args[,kwds]]):使??阻塞?式調(diào)?func(并?執(zhí)

?,堵塞?式必須等待上?個(gè)進(jìn)程退出才能執(zhí)?下?個(gè)進(jìn)程),args為

傳遞給func的參數(shù)列表,kwds為傳遞給func的關(guān)鍵字參數(shù)列表;apply(func[,args[,kwds]])(了解即可幾乎不用)使?阻塞?式調(diào)?funcclose():關(guān)閉Pool,使其不再接受新的任務(wù);terminate():不管任務(wù)是否完成,?即終?;join():主進(jìn)程阻塞,等待?進(jìn)程的退出,必須在close或terminate之后

使?;

進(jìn)程間通信-Queue多進(jìn)程之間,默認(rèn)是不共享數(shù)據(jù)的通過(guò)Queue(隊(duì)列Q)可以實(shí)現(xiàn)進(jìn)程間的數(shù)據(jù)傳遞Q本身是一個(gè)消息隊(duì)列如何添加消息(入隊(duì)操作):frommultiprocessingimportQueueq=Queue(3)#初始化一個(gè)Queue對(duì)象,最多可接受3條消息q.put(“消息1”)#添加的消息數(shù)據(jù)類型不限q.put("消息2")q.put("消息3")print(q.full())

進(jìn)程間通信-Queue可以使?multiprocessing模塊的Queue實(shí)現(xiàn)多進(jìn)程之間的數(shù)據(jù)傳遞初始化Queue()對(duì)象時(shí)(例如:q=Queue()),若括號(hào)中沒(méi)有指定最?可接收

的消息數(shù)量,或數(shù)量為負(fù)值,那么就代表可接受的消息數(shù)量沒(méi)有上限Queue.qsize():返回當(dāng)前隊(duì)列包含的消息數(shù)量Queue.empty():如果隊(duì)列為空,返回True,反之FalseQueue.full():如果隊(duì)列滿了,返回True,反之FalseQueue.get([block[,timeout]]):獲取隊(duì)列中的?條消息,然后將其從列隊(duì)

中移除,block默認(rèn)值為True如果block使?默認(rèn)值,且沒(méi)有設(shè)置timeout(單位秒),消息列隊(duì)如果為

空,此時(shí)程序?qū)⒈蛔枞ㄍT谧x取狀態(tài)),直到從消息列隊(duì)讀到消息為?,

如果設(shè)置了timeout,則會(huì)等待timeout秒,若還沒(méi)讀取到任何消息,則拋

出"Queue.Empty"異常如果block值為False,消息列隊(duì)如果為空,則會(huì)?刻拋

出“Queue.Empty”異常

進(jìn)程間通信-QueueQueue.get_nowait():相當(dāng)Queue.get(False)Queue.put(item,[block[,timeout]]):將item消息寫?隊(duì)列,block默認(rèn)值

為True如果block使?默認(rèn)值,且沒(méi)有設(shè)置timeout(單位秒),消息列隊(duì)如果已

經(jīng)沒(méi)有空間可寫?,此時(shí)程序?qū)⒈蛔枞ㄍT趯?狀態(tài)),直到從消息列隊(duì)

騰出空間為?,如果設(shè)置了True和timeout,則會(huì)等待timeout秒,若還沒(méi)空間,則拋

出"Queue.Full"異常如果block值為False,消息列隊(duì)如果沒(méi)有空間可寫?,則會(huì)?刻拋

出"Queue.Full"異常Queue.put_nowait(item):相當(dāng)Queue.put(item,False);

進(jìn)程間通信-QueuefrommultiprocessingimportQueue,Processimporttimedefwrite(q):forvaluein["a","b","c"]:print("開(kāi)始寫入:",value)q.put(value)time.sleep(1)defread(q):whileTrue:ifnotq.empty():print("讀取到的是",q.get())time.sleep(1)else:breakif__name__=="__main__":q=Queue()pw=Process(target=write,args=(q,))pr=Process(target=read,args=(q,))pw.start()pw.join()#等待接收完畢

pr.start()pr.join()print("接收完畢!")問(wèn)題:如果有兩個(gè)接收方怎么辦?(多任務(wù)之間配合)

進(jìn)程間通信-Queue

進(jìn)程池創(chuàng)建的進(jìn)程之間通信:如果要使?Pool創(chuàng)建進(jìn)程,就需要使?multiprocessing.Manager()中的Queue()

?不是multiprocessing.Queue()否則會(huì)得到?條如下的錯(cuò)誤信息:

RuntimeError:Queueobjectsshouldonlybesharedbetweenprocesses

throughinheritance.

進(jìn)程間通信-Queue

frommultiprocessingimportManager,Poolimporttimedefwriter(q):foriin"e":print("開(kāi)始寫入",i)q.put(i)defreader(q):time.sleep(3)foriinrange(q.qsize()):print("得到消息",q.get())

if__name__=="__main__":print("主進(jìn)程啟動(dòng)")q=Manager().Queue()po=Pool()po.apply_async(writer,(q,))po.apply_async(reader,(q,))po.close()po.join()

03多線程PARTTHREE多線程線程:實(shí)現(xiàn)多任務(wù)的另一種方式一個(gè)進(jìn)程中,也經(jīng)常需要同時(shí)做多件事,就需要同時(shí)運(yùn)行多個(gè)‘子任務(wù)’,這些子任務(wù),就是線程線程又被稱為輕量級(jí)進(jìn)程(lightweightprocess),是更小的執(zhí)行單元一個(gè)進(jìn)程可擁有多個(gè)并行的(concurrent)線程,當(dāng)中每一個(gè)線程,共享當(dāng)前進(jìn)程的資源一個(gè)進(jìn)程中的線程共享相同的內(nèi)存單元/內(nèi)存地址空間可以訪問(wèn)相同的變量和對(duì)象,而且它們從同一堆中分配對(duì)象通信、數(shù)據(jù)交換、同步操作由于線程間的通信是在同一地址空間上進(jìn)行的,所以不需要額外的通信機(jī)制,這就使得通信更簡(jiǎn)便而且信息傳遞的速度也更快線程和進(jìn)程的區(qū)別進(jìn)程是系統(tǒng)進(jìn)?資源分配和調(diào)度的?個(gè)獨(dú)?單位進(jìn)程在執(zhí)?過(guò)程中擁有獨(dú)?的內(nèi)存單元,?多個(gè)線程共享內(nèi)存,從?極

?地提?了程序的運(yùn)?效率?個(gè)程序?少有?個(gè)進(jìn)程,?個(gè)進(jìn)程?少有?個(gè)線程線程是進(jìn)程的?個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是?進(jìn)程更?的

能獨(dú)?運(yùn)?的基本單位線程??基本上不擁有系統(tǒng)資源,只擁有?點(diǎn)在運(yùn)?中必不可少的資源,但是它可與同屬?個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源線程的劃分尺度?于進(jìn)程(資源?進(jìn)程少),使得多線程程序的并發(fā)性?線程不能夠獨(dú)?執(zhí)?,必須依存在進(jìn)程中線程和進(jìn)程在使?上各有優(yōu)缺點(diǎn):線程執(zhí)?開(kāi)銷?,但不利于資源的管理和

保護(hù);?進(jìn)程正相反

線程和進(jìn)程的區(qū)別一般來(lái)講:我們把進(jìn)程用來(lái)分配資源,線程用來(lái)具體執(zhí)行(CPU調(diào)度)多線程python的thread模塊是?較底層的模塊,在各個(gè)操作系統(tǒng)中表現(xiàn)形式不同(低級(jí)模塊)python的threading模塊是對(duì)thread做了?些包裝的,可以更加?便的被使?(高級(jí)模塊)thread有一些缺點(diǎn),在threading得到了彌補(bǔ),所以我們直接學(xué)習(xí)threadingimportthreadingif__name__=="__main__":#任何進(jìn)程默認(rèn)會(huì)啟動(dòng)一個(gè)線程,這個(gè)線程稱為主線程,主線程可以啟動(dòng)新的子線程

#current_thread():返回當(dāng)前線程的實(shí)例

#.name:當(dāng)前線程的名稱

print('主線程%s啟動(dòng)'%(threading.current_thread().name))多線程importthreading,timedefsaySorry():print("子線程%s啟動(dòng)"%(threading.current_thread().name))time.sleep(1)print("親愛(ài)的,我錯(cuò)了,我能吃飯了嗎?")if__name__=="__main__":print('主線程%s啟動(dòng)'%(threading.current_thread().name))foriinrange(5):t=threading.Thread(target=saySorry)#Thread():指定線程要執(zhí)行的代碼

t.start()查看當(dāng)前線程數(shù)量importthreadingimporttimedefsing():foriinrange(3):print("正在唱歌...%d"%i)time.sleep(1)defdance():foriinrange(2):print("正在跳舞...%d"%i)time.sleep(1)if__name__=="__main__":print("開(kāi)始:%s"%time.time())t1=threading.Thread(target=sing)t2=threading.Thread(target=dance)t1.start()t2.start()whileTrue:length=len(threading.enumerate())#threading.enumerate():返回當(dāng)前運(yùn)行中的Thread對(duì)象列表

print("當(dāng)前線程數(shù)為:%d"%length)iflength<=1:breaktime.sleep(1)多線程創(chuàng)建線程的兩種方式:第一:通過(guò)threading.Thread直接在線程中運(yùn)行函數(shù);第二:通過(guò)繼承threading.Thread類來(lái)創(chuàng)建線程這種方法只需要重載threading.Thread類的run方法,然后調(diào)用start()開(kāi)啟線程就可以了importthreadingclassMyThread(threading.Thread):defrun(self):foriinrange(5):print(i)if__name__=="__main__":t1=MyThread()t2=MyThread()t1.start()t2.start()多線程importthreadingimporttimeclassMyThread(threading.Thread):defrun(self):foriinrange(3):time.sleep(1)msq="I`m"++"@"+str(i)#name屬性中保存了當(dāng)前線程的名字

print(msq)if__name__=="__main__":t=MyThread()t.start()線程的五種狀態(tài)

多線程程序的執(zhí)?順序是不確定的(操作系統(tǒng)決定)。當(dāng)執(zhí)?到sleep語(yǔ)句時(shí),線程將被阻塞(Blocked),到sleep結(jié)束后,線程進(jìn)?就緒(Runnable)狀態(tài),等待調(diào)度。?線程調(diào)度將??選擇?個(gè)線程執(zhí)?。代碼中只能保證每個(gè)線程都運(yùn)?完整個(gè)run函數(shù),但是線程的啟動(dòng)順序、run函數(shù)中每次循環(huán)的執(zhí)?順序都不能確定

線程的五種狀態(tài)

1、新?tīng)顟B(tài):線程對(duì)象已經(jīng)創(chuàng)建,還沒(méi)有在其上調(diào)用start()方法。2、可運(yùn)行狀態(tài):當(dāng)線程有資格運(yùn)行,但調(diào)度程序還沒(méi)有把它選定為運(yùn)行線程時(shí)線程所處的狀態(tài)。當(dāng)start()方法調(diào)用時(shí),線程首先進(jìn)入可運(yùn)行狀態(tài)。在線程運(yùn)行之后或者從阻塞、等待或睡眠狀態(tài)回來(lái)后,也返回到可運(yùn)行狀態(tài)。3、運(yùn)行狀態(tài):線程調(diào)度程序從可運(yùn)行池中選擇一個(gè)線程作為當(dāng)前線程時(shí)線程所處的狀態(tài)。這也是線程進(jìn)入運(yùn)行狀態(tài)的唯一一種方式。4、等待/阻塞/睡眠狀態(tài):這是線程有資格運(yùn)行時(shí)它所處的狀態(tài)。實(shí)際上這個(gè)三狀態(tài)組合為一種,其共同點(diǎn)是:線程仍舊是活的(可運(yùn)行的),但是當(dāng)前沒(méi)有條件運(yùn)行。但是如果某件事件出現(xiàn),他可能返回到可運(yùn)行狀態(tài)。5、死亡態(tài):當(dāng)線程的run()方法完成時(shí)就認(rèn)為它死去。這個(gè)線程對(duì)象也許是活的,但是,它已經(jīng)不是一個(gè)單獨(dú)執(zhí)行的線程。線程一旦死亡,就不能復(fù)生。如果在一個(gè)死去的線程上調(diào)用start()方法,會(huì)拋出RuntimeError:threadscanonlybestartedonce異常。

線程共享全局變量在?個(gè)進(jìn)程內(nèi)的所有線程共享全局變量,多線程之間的數(shù)據(jù)共享(這點(diǎn)要?多進(jìn)程要好)缺點(diǎn)就是,可能造成多個(gè)線程同時(shí)修改一個(gè)變量(即線程?安全),可能造成混亂

線程共享全局變量importthreadingimporttimenum=100defwork1():globalnumforiinrange(3):num+=1print("---inwork1,numis%d"%num)defwork2():globalnumprint("---inwork2,numis%d"%num)

print("---線程創(chuàng)建之前numis%d"%num)t1=threading.Thread(target=work1)t1.start()time.sleep(1)#延時(shí)一會(huì)保證線程1中的任務(wù)做完t2=threading.Thread(target=work2)t2.start()

線程共享全局變量importthreading,timedefwork1(nums):nums.append(44)print('-----inwork1-----',nums)defwork2(nums):time.sleep(1)#延時(shí)一會(huì)保證另一線程執(zhí)行

print('-----inwork2-----',nums)g_nums=[11,22,33]t1=threading.Thread(target=work1,args=(g_nums,))t1.start()t2=threading.Thread(target=work2,args=(g_nums,))t2.start()

執(zhí)行1000000次的bugimportthreadingnum=0deftest1():globalnumforiinrange(100):#一百萬(wàn)錯(cuò)誤

num+=1deftest2():globalnumforiinrange(100):#一百萬(wàn)錯(cuò)誤

num+=1p1=threading.Thread(target=test1)p1.start()p2=threading.Thread(target=test2)p2.start()print("---num=%d---"%num)

04線程同步PARTFOUR線程同步當(dāng)多個(gè)線程?乎同時(shí)修改某?個(gè)共享數(shù)據(jù)的時(shí)候,需要進(jìn)?同步控制線程同步能夠保證多個(gè)線程安全訪問(wèn)競(jìng)爭(zhēng)資源,最簡(jiǎn)單的同步機(jī)制是引?互

斥鎖互斥鎖保證了每次只有?個(gè)線程進(jìn)?寫?操作,從?保證了多線程情況下數(shù)據(jù)的正確性(原子性)互斥鎖為資源引入一個(gè)狀態(tài):鎖定/非鎖定。某個(gè)線程要更改共享數(shù)據(jù)時(shí),先將其鎖定,此時(shí)資源的狀態(tài)為“鎖定”,其他線程不能更改;直到該線程釋放資源,將資源的狀態(tài)變成“非鎖定”,其他的線程才能再次鎖定該資源。互斥鎖保證了每次只有一個(gè)線程進(jìn)行寫入操作,從而保證了多線程情況下數(shù)據(jù)的正確性。

threading模塊中定義了Lock類,可以?便的處理鎖定

線程同步創(chuàng)建鎖

mutex=threading.Lock()鎖定

mutex.acquire()

釋放

mutex.release()#解鎖

線程同步-互斥鎖importthreadingnum=0deftest1():globalnumifmutex.acquire():foriinrange(1000):

num+=1mutex.release()deftest2():globalnumifmutex.acquire():foriinrange(1000):

num+=1mutex.release()

當(dāng)一個(gè)線程調(diào)用Lock對(duì)象的acquire()方法獲得鎖時(shí),這把鎖就進(jìn)入“l(fā)ocked”狀態(tài)。因?yàn)槊看沃挥幸粋€(gè)線程可以獲得鎖,所以如果此時(shí)另一個(gè)線程2試圖獲得這個(gè)鎖,該線程2就會(huì)變?yōu)橥阶枞麪顟B(tài)直到擁有鎖的線程1調(diào)用鎖的release()方法釋放鎖之后,該鎖進(jìn)入“unlocked”狀態(tài)。線程調(diào)度程序繼續(xù)從處于同步阻塞狀態(tài)的線程中選擇一個(gè)來(lái)獲得鎖,并使得該線程進(jìn)入運(yùn)行(running)狀態(tài)一個(gè)線程有鎖時(shí)別的線程只能在外面等著mutex=threading.Lock()p1=threading.Thread(target=test1)p1.start()p2=threading.Thread(target=test2)p2.start()print(num)線程同步(死鎖)死鎖(錯(cuò)誤情況,理解即可)

在線程間共享多個(gè)資源的時(shí)候,如果兩個(gè)線程分別占有?部分資源并且同時(shí)

等待對(duì)?的資源,就會(huì)造成死鎖?到了死鎖狀態(tài),可以使?ctrl-z退出

線程同步(死鎖)

importthreadingimporttimeclassMyThread1(threading.Thread):defrun(self):ifmutexA.acquire():print(+'---do1---up---')time.sleep(1)ifmutexB.acquire():print(+'---do1---down---')mutexB.release()mutexA.release()classMyThread2(threading.Thread):defrun(self): time.sleep(1) ifmutexB.acquire(): print(+'---do2---up---') ifmutexA.acquire(): print(+'---do2---down---') mutexA.release() mutexB.release()if__name__=='__main__':mutexA=threading.Lock()mutexB=threading.Lock()t1=MyThread1()t2=MyThread2()t1.start()t2.start()在多線程程序中,死鎖問(wèn)題很大一部分是由于線程同時(shí)獲取多個(gè)鎖造成的。如一個(gè)線程獲取了第一個(gè)鎖,然后在獲取第二個(gè)鎖的時(shí)候發(fā)生阻塞,那么這個(gè)線程就可能阻塞其他線程的執(zhí)行,從而導(dǎo)致整個(gè)程序假死(兩個(gè)人每人一根筷子)同步和異步同步調(diào)?:確定調(diào)用的順序按順序購(gòu)買四大名著異步調(diào)?:不確定順序你喊你朋友吃飯,你朋友說(shuō)知道了,待會(huì)忙完去找你,你就去做別的了堵塞和非堵塞

線程同步-多個(gè)線程有序執(zhí)?

importthreading,timeclassTask1(threading.Thread):defrun(self):whileTrue:iflock1.acquire():print('-----Task1-----')time.sleep(1)lock2.release()classTask2(threading.Thread):defrun(self):whileTrue:iflock2.acquire():print('-----Task2-----')time.sleep(1)lock3.release()classTask3(threading.Thread):defrun(self):whileTrue:iflock3.acquire():print('-----Task3-----')time.sleep(1)lock1.release()lock1=threading.Lock()#創(chuàng)建另外一把鎖,并且鎖上lock2=threading.Lock()lock2.acquire()#再創(chuàng)建一把鎖并鎖上lock3=threading.Lock()lock3.acquire()t1=Task1()t2=Task2()t3=Task3()t1.start()t2.start()t3.start()無(wú)序執(zhí)行,方式很多

importthreading,timenum=0deftest1():globalnummutex.acquire()foriinrange(1000000):num+=1mutex.release()print("1",num)deftest2():globalnumwhileTrue:ifmutex.acquire(False):foriinrange(1000000):num+=1print("2",num)mutex.release()breakelse:print("該干嘛干嘛")mutex=threading.Lock()p1=threading.Thread(target=test1)p2=threading.Thread(target=test2)p1.start()p2.start()?產(chǎn)者消費(fèi)者模式?產(chǎn)者消費(fèi)者模式在線程世界?,?產(chǎn)者就是?產(chǎn)數(shù)據(jù)的線程,消費(fèi)者就是消費(fèi)數(shù)據(jù)的線程(做包子,吃包子)經(jīng)常會(huì)出現(xiàn)生產(chǎn)數(shù)據(jù)的速度大于消費(fèi)數(shù)據(jù)的速度,或者生產(chǎn)速度跟不上消費(fèi)速度?產(chǎn)者消費(fèi)者模式是通過(guò)?個(gè)容器(緩沖區(qū))來(lái)解決?產(chǎn)者和消費(fèi)者的強(qiáng)耦合問(wèn)題例如兩個(gè)線程共同操作一個(gè)列表,一個(gè)放數(shù)據(jù),一個(gè)取數(shù)據(jù)?產(chǎn)者和消費(fèi)者彼此之間不直接通訊,?通過(guò)阻塞隊(duì)列來(lái)進(jìn)?通訊

線程同步Python的Queue模塊:實(shí)現(xiàn)了3種類型的隊(duì)列來(lái)實(shí)現(xiàn)線程同步,包括:FIFO(先?先出)隊(duì)列Queue,LIFO(后?先出)棧LifoQueue,優(yōu)先級(jí)隊(duì)列PriorityQueue區(qū)別在于隊(duì)列中條目檢索的順序不同在FIFO隊(duì)列中,按照先進(jìn)先出的順序檢索條目在LIFO隊(duì)列中,最后添加的條目最先檢索到(操作類似一個(gè)棧)在優(yōu)先級(jí)隊(duì)列中,條目被保存為有序的(使用heapq模塊)并且最小值的條目被最先檢索這些隊(duì)列都實(shí)現(xiàn)了鎖原語(yǔ)(可以理解為原?操作,即要么不做,要么就做完),能夠在多線程中直接使?現(xiàn)階段只要求掌握其中一種,F(xiàn)IFO隊(duì)列

線程同步classqueue.Queue(maxsize=0)FIFO隊(duì)列的構(gòu)造器。maxsize為一個(gè)整數(shù),表示隊(duì)列的最大條目數(shù),可用來(lái)限制內(nèi)存的使用。一旦隊(duì)列滿,插入將被阻塞直到隊(duì)列中存在空閑空間。如果maxsize小于等于0,隊(duì)列大小為無(wú)限。maxsize默認(rèn)為0

線程同步-隊(duì)列importthreadingimporttimef

溫馨提示

  • 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)論