日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

Python多线程学习

發(fā)布時(shí)間:2025/7/14 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python多线程学习 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?一、Python中的線(xiàn)程使用:

????Python中使用線(xiàn)程有兩種方式:函數(shù)或者用類(lèi)來(lái)包裝線(xiàn)程對(duì)象。

1、??函數(shù)式:調(diào)用thread模塊中的start_new_thread()函數(shù)來(lái)產(chǎn)生新線(xiàn)程。如下例:

?

  • import?time??
  • import?thread??
  • def?timer(no,?interval):??
  • ????cnt?=?0??
  • ????while?cnt<10:??
  • ????????print?'Thread:(%d)?Time:%s\n'%(no,?time.ctime())??
  • ????????time.sleep(interval)??
  • ????????cnt+=1??
  • ????thread.exit_thread()??
  • ?????
  • ???
  • def?test():?#Use?thread.start_new_thread()?to?create?2?new?threads??
  • ????thread.start_new_thread(timer,?(1,1))??
  • ????thread.start_new_thread(timer,?(2,2))??
  • ???
  • if?__name__=='__main__':??
  • ????test()??
  • ?

    ?

    ????上面的例子定義了一個(gè)線(xiàn)程函數(shù)timer,它打印出10條時(shí)間記錄后退出,每次打印的間隔由interval參數(shù)決定。thread.start_new_thread(function, args[, kwargs])的第一個(gè)參數(shù)是線(xiàn)程函數(shù)(本例中的timer方法),第二個(gè)參數(shù)是傳遞給線(xiàn)程函數(shù)的參數(shù),它必須是tuple類(lèi)型,kwargs是可選參數(shù)。

    ????線(xiàn)程的結(jié)束可以等待線(xiàn)程自然結(jié)束,也可以在線(xiàn)程函數(shù)中調(diào)用thread.exit()或thread.exit_thread()方法。

    2、??創(chuàng)建threading.Thread的子類(lèi)來(lái)包裝一個(gè)線(xiàn)程對(duì)象,如下例:

    ?

  • import?threading??
  • import?time??
  • class?timer(threading.Thread):?#The?timer?class?is?derived?from?the?class?threading.Thread??
  • ????def?__init__(self,?num,?interval):??
  • ????????threading.Thread.__init__(self)??
  • ????????self.thread_num?=?num??
  • ????????self.interval?=?interval??
  • ????????self.thread_stop?=?False??
  • ???
  • ????def?run(self):?#Overwrite?run()?method,?put?what?you?want?the?thread?do?here??
  • ????????while?not?self.thread_stop:??
  • ????????????print?'Thread?Object(%d),?Time:%s\n'?%(self.thread_num,?time.ctime())??
  • ????????????time.sleep(self.interval)??
  • ????def?stop(self):??
  • ????????self.thread_stop?=?True??
  • ?????????
  • ???
  • def?test():??
  • ????thread1?=?timer(1,?1)??
  • ????thread2?=?timer(2,?2)??
  • ????thread1.start()??
  • ????thread2.start()??
  • ????time.sleep(10)??
  • ????thread1.stop()??
  • ????thread2.stop()??
  • ????return??
  • ???
  • if?__name__?==?'__main__':??
  • ????test()??
  • ?

    ?

    ???

    ????就我個(gè)人而言,比較喜歡第二種方式,即創(chuàng)建自己的線(xiàn)程類(lèi),必要時(shí)重寫(xiě)threading.Thread類(lèi)的方法,線(xiàn)程的控制可以由自己定制。

    threading.Thread類(lèi)的使用:

    1,在自己的線(xiàn)程類(lèi)的__init__里調(diào)用threading.Thread.__init__(self, name = threadname)

    Threadname為線(xiàn)程的名字

    2,?run(),通常需要重寫(xiě),編寫(xiě)代碼實(shí)現(xiàn)做需要的功能。

    3,getName(),獲得線(xiàn)程對(duì)象名稱(chēng)

    4,setName(),設(shè)置線(xiàn)程對(duì)象名稱(chēng)

    5,start(),啟動(dòng)線(xiàn)程

    6,jion([timeout]),等待另一線(xiàn)程結(jié)束后再運(yùn)行。

    7,setDaemon(bool),設(shè)置子線(xiàn)程是否隨主線(xiàn)程一起結(jié)束,必須在start()之前調(diào)用。默認(rèn)為False。

    8,isDaemon(),判斷線(xiàn)程是否隨主線(xiàn)程一起結(jié)束。

    9,isAlive(),檢查線(xiàn)程是否在運(yùn)行中。

    ????此外threading模塊本身也提供了很多方法和其他的類(lèi),可以幫助我們更好的使用和管理線(xiàn)程。可以參看http://www.python.org/doc/2.5.2/lib/module-threading.html。

    ?

    ?

    假設(shè)兩個(gè)線(xiàn)程對(duì)象t1和t2都要對(duì)num=0進(jìn)行增1運(yùn)算,t1和t2都各對(duì)num修改10次,num的最終的結(jié)果應(yīng)該為20。但是由于是多線(xiàn)程訪(fǎng)問(wèn),有可能出現(xiàn)下面情況:在num=0時(shí),t1取得num=0。系統(tǒng)此時(shí)把t1調(diào)度為”sleeping”狀態(tài),把t2轉(zhuǎn)換為”running”狀態(tài),t2頁(yè)獲得num=0。然后t2對(duì)得到的值進(jìn)行加1并賦給num,使得num=1。然后系統(tǒng)又把t2調(diào)度為”sleeping”,把t1轉(zhuǎn)為”running”。線(xiàn)程t1又把它之前得到的0加1后賦值給num。這樣,明明t1和t2都完成了1次加1工作,但結(jié)果仍然是num=1。

    ????上面的case描述了多線(xiàn)程情況下最常見(jiàn)的問(wèn)題之一:數(shù)據(jù)共享。當(dāng)多個(gè)線(xiàn)程都要去修改某一個(gè)共享數(shù)據(jù)的時(shí)候,我們需要對(duì)數(shù)據(jù)訪(fǎng)問(wèn)進(jìn)行同步。

    1、??簡(jiǎn)單的同步

    最簡(jiǎn)單的同步機(jī)制就是“鎖”。鎖對(duì)象由threading.RLock類(lèi)創(chuàng)建。線(xiàn)程可以使用鎖的acquire()方法獲得鎖,這樣鎖就進(jìn)入“l(fā)ocked”狀態(tài)。每次只有一個(gè)線(xiàn)程可以獲得鎖。如果當(dāng)另一個(gè)線(xiàn)程試圖獲得這個(gè)鎖的時(shí)候,就會(huì)被系統(tǒng)變?yōu)椤癰locked”狀態(tài),直到那個(gè)擁有鎖的線(xiàn)程調(diào)用鎖的release()方法來(lái)釋放鎖,這樣鎖就會(huì)進(jìn)入“unlocked”狀態(tài)。“blocked”狀態(tài)的線(xiàn)程就會(huì)收到一個(gè)通知,并有權(quán)利獲得鎖。如果多個(gè)線(xiàn)程處于“blocked”狀態(tài),所有線(xiàn)程都會(huì)先解除“blocked”狀態(tài),然后系統(tǒng)選擇一個(gè)線(xiàn)程來(lái)獲得鎖,其他的線(xiàn)程繼續(xù)沉默(“blocked”)。

    Python中的thread模塊和Lock對(duì)象是Python提供的低級(jí)線(xiàn)程控制工具,使用起來(lái)非常簡(jiǎn)單。如下例所示:

    ?

  • import?thread??
  • import?time??
  • mylock?=?thread.allocate_lock()??#Allocate?a?lock??
  • num=0??#Shared?resource??
  • ??
  • def?add_num(name):??
  • ????global?num??
  • ????while?True:??
  • ????????mylock.acquire()?#Get?the?lock???
  • ????????#?Do?something?to?the?shared?resource??
  • ????????print?'Thread?%s?locked!?num=%s'%(name,str(num))??
  • ????????if?num?>=?5:??
  • ????????????print?'Thread?%s?released!?num=%s'%(name,str(num))??
  • ????????????mylock.release()??
  • ????????????thread.exit_thread()??
  • ????????num+=1??
  • ????????print?'Thread?%s?released!?num=%s'%(name,str(num))??
  • ????????mylock.release()??#Release?the?lock.??
  • ??
  • def?test():??
  • ????thread.start_new_thread(add_num,?('A',))??
  • ????thread.start_new_thread(add_num,?('B',))??
  • ??
  • if?__name__==?'__main__':??
  • ????test()??
  • ?

    Python?在thread的基礎(chǔ)上還提供了一個(gè)高級(jí)的線(xiàn)程控制庫(kù),就是之前提到過(guò)的threading。Python的threading module是在建立在thread module基礎(chǔ)之上的一個(gè)module,在threading module中,暴露了許多thread module中的屬性。在thread module中,python提供了用戶(hù)級(jí)的線(xiàn)程同步工具“Lock”對(duì)象。而在threading module中,python又提供了Lock對(duì)象的變種: RLock對(duì)象。RLock對(duì)象內(nèi)部維護(hù)著一個(gè)Lock對(duì)象,它是一種可重入的對(duì)象。對(duì)于Lock對(duì)象而言,如果一個(gè)線(xiàn)程連續(xù)兩次進(jìn)行acquire操作,那么由于第一次acquire之后沒(méi)有release,第二次acquire將掛起線(xiàn)程。這會(huì)導(dǎo)致Lock對(duì)象永遠(yuǎn)不會(huì)release,使得線(xiàn)程死鎖。RLock對(duì)象允許一個(gè)線(xiàn)程多次對(duì)其進(jìn)行acquire操作,因?yàn)樵谄鋬?nèi)部通過(guò)一個(gè)counter變量維護(hù)著線(xiàn)程acquire的次數(shù)。而且每一次的acquire操作必須有一個(gè)release操作與之對(duì)應(yīng),在所有的release操作完成之后,別的線(xiàn)程才能申請(qǐng)?jiān)揜Lock對(duì)象。

    下面來(lái)看看如何使用threading的RLock對(duì)象實(shí)現(xiàn)同步。

    ?

  • import?threading??
  • mylock?=?threading.RLock()??
  • num=0??
  • ???
  • class?myThread(threading.Thread):??
  • ????def?__init__(self,?name):??
  • ????????threading.Thread.__init__(self)??
  • ????????self.t_name?=?name??
  • ??????????
  • ????def?run(self):??
  • ????????global?num??
  • ????????while?True:??
  • ????????????mylock.acquire()??
  • ????????????print?'\nThread(%s)?locked,?Number:?%d'%(self.t_name,?num)??
  • ????????????if?num>=4:??
  • ????????????????mylock.release()??
  • ????????????????print?'\nThread(%s)?released,?Number:?%d'%(self.t_name,?num)??
  • ????????????????break??
  • ????????????num+=1??
  • ????????????print?'\nThread(%s)?released,?Number:?%d'%(self.t_name,?num)??
  • ????????????mylock.release()??
  • ??????????????
  • def?test():??
  • ????thread1?=?myThread('A')??
  • ????thread2?=?myThread('B')??
  • ????thread1.start()??
  • ????thread2.start()??
  • ???
  • if?__name__==?'__main__':??
  • ????test()??
  • ?

    我們把修改共享數(shù)據(jù)的代碼成為“臨界區(qū)”。必須將所有“臨界區(qū)”都封閉在同一個(gè)鎖對(duì)象的acquire和release之間。

    2、??條件同步

    鎖只能提供最基本的同步。假如只在發(fā)生某些事件時(shí)才訪(fǎng)問(wèn)一個(gè)“臨界區(qū)”,這時(shí)需要使用條件變量Condition。

    Condition對(duì)象是對(duì)Lock對(duì)象的包裝,在創(chuàng)建Condition對(duì)象時(shí),其構(gòu)造函數(shù)需要一個(gè)Lock對(duì)象作為參數(shù),如果沒(méi)有這個(gè)Lock對(duì)象參數(shù),Condition將在內(nèi)部自行創(chuàng)建一個(gè)Rlock對(duì)象。在Condition對(duì)象上,當(dāng)然也可以調(diào)用acquire和release操作,因?yàn)閮?nèi)部的Lock對(duì)象本身就支持這些操作。但是Condition的價(jià)值在于其提供的wait和notify的語(yǔ)義。

    條件變量是如何工作的呢?首先一個(gè)線(xiàn)程成功獲得一個(gè)條件變量后,調(diào)用此條件變量的wait()方法會(huì)導(dǎo)致這個(gè)線(xiàn)程釋放這個(gè)鎖,并進(jìn)入“blocked”狀態(tài),直到另一個(gè)線(xiàn)程調(diào)用同一個(gè)條件變量的notify()方法來(lái)喚醒那個(gè)進(jìn)入“blocked”狀態(tài)的線(xiàn)程。如果調(diào)用這個(gè)條件變量的notifyAll()方法的話(huà)就會(huì)喚醒所有的在等待的線(xiàn)程。

    如果程序或者線(xiàn)程永遠(yuǎn)處于“blocked”狀態(tài)的話(huà),就會(huì)發(fā)生死鎖。所以如果使用了鎖、條件變量等同步機(jī)制的話(huà),一定要注意仔細(xì)檢查,防止死鎖情況的發(fā)生。對(duì)于可能產(chǎn)生異常的臨界區(qū)要使用異常處理機(jī)制中的finally子句來(lái)保證釋放鎖。等待一個(gè)條件變量的線(xiàn)程必須用notify()方法顯式的喚醒,否則就永遠(yuǎn)沉默。保證每一個(gè)wait()方法調(diào)用都有一個(gè)相對(duì)應(yīng)的notify()調(diào)用,當(dāng)然也可以調(diào)用notifyAll()方法以防萬(wàn)一。

    ?

    ?

    生產(chǎn)者與消費(fèi)者問(wèn)題是典型的同步問(wèn)題。這里簡(jiǎn)單介紹兩種不同的實(shí)現(xiàn)方法。

    1,??條件變量

    ?

  • import?threading??
  • ??
  • import?time??
  • ??
  • class?Producer(threading.Thread):??
  • ??
  • ????def?__init__(self,?t_name):??
  • ??
  • ????????threading.Thread.__init__(self,?name=t_name)??
  • ??
  • ???
  • ??
  • ????def?run(self):??
  • ??
  • ????????global?x??
  • ??
  • ????????con.acquire()??
  • ??
  • ????????if?x?>?0:??
  • ??
  • ????????????con.wait()??
  • ??
  • ????????else:??
  • ??
  • ????????????for?i?in?range(5):??
  • ??
  • ????????????????x=x+1??
  • ??
  • ????????????????print?"producing..."?+?str(x)??
  • ??
  • ????????????con.notify()??
  • ??
  • ????????print?x??
  • ??
  • ????????con.release()??
  • ??
  • ???
  • ??
  • class?Consumer(threading.Thread):??
  • ??
  • ????def?__init__(self,?t_name):??
  • ??
  • ????????threading.Thread.__init__(self,?name=t_name)??
  • ??
  • ????def?run(self):??
  • ??
  • ????????global?x??
  • ??
  • ????????con.acquire()??
  • ??
  • ????????if?x?==?0:??
  • ??
  • ????????????print?'consumer?wait1'??
  • ??
  • ????????????con.wait()??
  • ??
  • ????????else:??
  • ??
  • ????????????for?i?in?range(5):??
  • ??
  • ????????????????x=x-1??
  • ??
  • ????????????????print?"consuming..."?+?str(x)??
  • ??
  • ????????????con.notify()??
  • ??
  • ????????print?x??
  • ??
  • ????????con.release()??
  • ??
  • ???
  • ??
  • con?=?threading.Condition()??
  • ??
  • x=0??
  • ??
  • print?'start?consumer'??
  • ??
  • c=Consumer('consumer')??
  • ??
  • print?'start?producer'??
  • ??
  • p=Producer('producer')??
  • ??
  • ???
  • ??
  • p.start()??
  • ??
  • c.start()??
  • ??
  • p.join()??
  • ??
  • c.join()??
  • ??
  • print?x??
  • ??

    ?

    ?

    ????上面的例子中,在初始狀態(tài)下,Consumer處于wait狀態(tài),Producer連續(xù)生產(chǎn)(對(duì)x執(zhí)行增1操作)5次后,notify正在等待的Consumer。Consumer被喚醒開(kāi)始消費(fèi)(對(duì)x執(zhí)行減1操作)?

    2,??同步隊(duì)列

    Python中的Queue對(duì)象也提供了對(duì)線(xiàn)程同步的支持。使用Queue對(duì)象可以實(shí)現(xiàn)多個(gè)生產(chǎn)者和多個(gè)消費(fèi)者形成的FIFO的隊(duì)列。

    生產(chǎn)者將數(shù)據(jù)依次存入隊(duì)列,消費(fèi)者依次從隊(duì)列中取出數(shù)據(jù)。

    ?

    ?

  • #?producer_consumer_queue??
  • ??
  • from?Queue?import?Queue??
  • ??
  • import?random??
  • ??
  • import?threading??
  • ??
  • import?time??
  • ??
  • ???
  • ??
  • #Producer?thread??
  • ??
  • class?Producer(threading.Thread):??
  • ??
  • ????def?__init__(self,?t_name,?queue):??
  • ??
  • ????????threading.Thread.__init__(self,?name=t_name)??
  • ??
  • ????????self.data=queue??
  • ??
  • ????def?run(self):??
  • ??
  • ????????for?i?in?range(5):??
  • ??
  • ????????????print?"%s:?%s?is?producing?%d?to?the?queue!\n"?%(time.ctime(),?self.getName(),?i)??
  • ??
  • ????????????self.data.put(i)??
  • ??
  • ????????????time.sleep(random.randrange(10)/5)??
  • ??
  • ????????print?"%s:?%s?finished!"?%(time.ctime(),?self.getName())??
  • ??
  • ???
  • ??
  • #Consumer?thread??
  • ??
  • class?Consumer(threading.Thread):??
  • ??
  • ????def?__init__(self,?t_name,?queue):??
  • ??
  • ????????threading.Thread.__init__(self,?name=t_name)??
  • ??
  • ????????self.data=queue??
  • ??
  • ????def?run(self):??
  • ??
  • ????????for?i?in?range(5):??
  • ??
  • ????????????val?=?self.data.get()??
  • ??
  • ????????????print?"%s:?%s?is?consuming.?%d?in?the?queue?is?consumed!\n"?%(time.ctime(),?self.getName(),?val)??
  • ??
  • ????????????time.sleep(random.randrange(10))??
  • ??
  • ????????print?"%s:?%s?finished!"?%(time.ctime(),?self.getName())??
  • ??
  • ???
  • ??
  • #Main?thread??
  • ??
  • def?main():??
  • ??
  • ????queue?=?Queue()??
  • ??
  • ????producer?=?Producer('Pro.',?queue)??
  • ??
  • ????consumer?=?Consumer('Con.',?queue)??
  • ??
  • ????producer.start()??
  • ??
  • ????consumer.start()??
  • ??
  • ????producer.join()??
  • ??
  • ????consumer.join()??
  • ??
  • ????print?'All?threads?terminate!'??
  • ??
  • ???
  • ??
  • if?__name__?==?'__main__':??
  • ??
  • ????main()??
  • ?

    ?

    在上面的例子中,Producer在隨機(jī)的時(shí)間內(nèi)生產(chǎn)一個(gè)“產(chǎn)品”,放入隊(duì)列中。Consumer發(fā)現(xiàn)隊(duì)列中有了“產(chǎn)品”,就去消費(fèi)它。本例中,由于Producer生產(chǎn)的速度快于Consumer消費(fèi)的速度,所以往往Producer生產(chǎn)好幾個(gè)“產(chǎn)品”后,Consumer才消費(fèi)一個(gè)產(chǎn)品。

    Queue模塊實(shí)現(xiàn)了一個(gè)支持多producer和多consumer的FIFO隊(duì)列。當(dāng)共享信息需要安全的在多線(xiàn)程之間交換時(shí),Queue非常有用。Queue的默認(rèn)長(zhǎng)度是無(wú)限的,但是可以設(shè)置其構(gòu)造函數(shù)的maxsize參數(shù)來(lái)設(shè)定其長(zhǎng)度。Queue的put方法在隊(duì)尾插入,該方法的原型是:

    put(?item[, block[, timeout]])

    如果可選參數(shù)block為true并且timeout為None(缺省值),線(xiàn)程被block,直到隊(duì)列空出一個(gè)數(shù)據(jù)單元。如果timeout大于0,在timeout的時(shí)間內(nèi),仍然沒(méi)有可用的數(shù)據(jù)單元,Full exception被拋出。反之,如果block參數(shù)為false(忽略timeout參數(shù)),item被立即加入到空閑數(shù)據(jù)單元中,如果沒(méi)有空閑數(shù)據(jù)單元,Full exception被拋出。

    Queue的get方法是從隊(duì)首取數(shù)據(jù),其參數(shù)和put方法一樣。如果block參數(shù)為true且timeout為None(缺省值),線(xiàn)程被block,直到隊(duì)列中有數(shù)據(jù)。如果timeout大于0,在timeout時(shí)間內(nèi),仍然沒(méi)有可取數(shù)據(jù),Empty exception被拋出。反之,如果block參數(shù)為false(忽略timeout參數(shù)),隊(duì)列中的數(shù)據(jù)被立即取出。如果此時(shí)沒(méi)有可取數(shù)據(jù),Empty exception也會(huì)被拋出。

    轉(zhuǎn)載于:https://www.cnblogs.com/imhurley/p/3803271.html

    總結(jié)

    以上是生活随笔為你收集整理的Python多线程学习的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。