python并发入门(part5 event对象)
?
一、引入event。?
每個(gè)線程,都是一個(gè)獨(dú)立運(yùn)行的個(gè)體,并且每個(gè)線程的運(yùn)行狀態(tài)是無(wú)法預(yù)測(cè)的。?
如果一個(gè)程序中有很多個(gè)線程,程序的其他線程需要判斷某個(gè)線程的運(yùn)行狀態(tài),來(lái)確定自己下一步要執(zhí)行哪些操作。?
threading模塊中的event對(duì)象恰好能做到這一點(diǎn),event對(duì)象包含了一個(gè)可以通過(guò)線程設(shè)置的一個(gè)信號(hào)標(biāo)志位,它允許線程一直等待某些事件的發(fā)生。?
在初始化默認(rèn)的情況下,event對(duì)象中的信號(hào)標(biāo)識(shí)被設(shè)置為“假”,如果這時(shí),有一個(gè)線程等待這個(gè)event對(duì)象,而這個(gè)event對(duì)象的信號(hào)標(biāo)志為“假”,那么這個(gè)線程就會(huì)被一直阻塞下去,直到這個(gè)event信號(hào)標(biāo)志為“真”,所有等待這個(gè)event對(duì)象的線程才會(huì)被喚醒。?
也就是說(shuō),一個(gè)線程如果等待的event對(duì)象中的信號(hào)標(biāo)志位“真”,這個(gè)線程會(huì)忽略這個(gè)事件(event),繼續(xù)執(zhí)行。?
二、event對(duì)象的常用方法。?
event.isSet():返回event的狀態(tài)值。?
event.wait():?當(dāng)event對(duì)象內(nèi)部的信號(hào)標(biāo)識(shí)設(shè)置為“假”(False),所有等待這個(gè)event對(duì)象的線程將會(huì)全部被阻塞。?
event.set():設(shè)置event對(duì)象內(nèi)部的信號(hào)標(biāo)識(shí)為“真”(True),所有等待這個(gè)event對(duì)象的線程將會(huì)被喚醒,等待操作系統(tǒng)的調(diào)度。?
event.clear():恢復(fù)event的狀態(tài)值為False。?
三、event使用示例。?
我們來(lái)考慮下event對(duì)象的應(yīng)用場(chǎng)景。?
假如,在一個(gè)程序中,有多個(gè)線程需要到redis中來(lái)取數(shù)據(jù),每個(gè)線程都要去嘗試著去連接redis服務(wù)器,一般情況下,redis如果連接不成功,在所有線程中都需要嘗試著去重新連接。?
如果我們想要在程序啟動(dòng)時(shí),先要確保redis服務(wù)器工作正常,接著在讓其他工作的線程去連接redis服務(wù)器,當(dāng)遇到這種需求的時(shí)候,使用event對(duì)象就是一個(gè)非常不錯(cuò)的選擇。?
我們可以使用event機(jī)制去讓各個(gè)工作的線程去做一個(gè)簡(jiǎn)單的通信,主線程去連接redis服務(wù)器,如果連接到了,event對(duì)象內(nèi)的信號(hào)標(biāo)識(shí)改為真,其余工作的線程就會(huì)被喚醒。?
示例:?
#!/usr/local/bin/python2.7?
# -*- coding:utf-8 -*-?
import threading?
import time?
import logging?
logging.basicConfig(level=logging.DEBUG, format='(%(threadName)-10s) %(message)s',)?
def worker(event):?
??logging.debug("waiting for redis ready....")?
??event.wait()?
??logging.debug("redis ready,and connect to redis server and do some work %s",time.ctime())?
??time.sleep(1)?
def main():?
??redis_ready = threading.Event()?
??t1 = threading.Thread(target=worker,args=(redis_ready,),name="threading-1")?
??t1.start()?
??t2 = threading.Thread(target=worker,args=(redis_ready,),name="threading-2")?
??t2.start()?
??logging.debug("first of all,check redis server, make sure it is ok , and then trigger the redis ready event")?
??time.sleep(3)?
??redis_ready.set()?
if __name__ == '__main__':?
??main()?
輸出結(jié)果:?
(threading-1) waiting for redis ready....?
(threading-2) waiting for redis ready....?
(MainThread) first of all,check redis server, make sure it is ok , and then trigger the redis ready event?
(threading-1) redis ready,and connect to redis server and do some work Sun May 14 09:35:46 2017?
(threading-2) redis ready,and connect to redis server and do some work Sun May 14 09:35:46 2017?
代碼分析:?
在上面這段代碼中,一共開(kāi)了三個(gè)線程,分別是threading-1和threading-2還有主線程,首先主線程運(yùn)行了main()函數(shù),產(chǎn)生了一個(gè)event對(duì)象,這個(gè)event對(duì)象信號(hào)的初始值是False,然后創(chuàng)建了threading-1和threading-2兩個(gè)線程并且運(yùn)行,輸出一條日志first of all,check redis server, make sure it is ok , and then trigger the redis ready event后sleep 3秒,此時(shí)切換到了threading-1,threading-1首先執(zhí)行了worker函數(shù),輸出一次日志,然后執(zhí)行event.wait方法,當(dāng)這個(gè)event對(duì)象的信號(hào)標(biāo)識(shí)為False時(shí),threading-1就被阻塞住了,暫時(shí)無(wú)法執(zhí)行woker函數(shù)后面的內(nèi)容,當(dāng)threading-1被阻塞住后,隨即切換到threading-2(為什么一定切換到threading-2呢?這是因?yàn)橹骶€程還在sleep),threading-2此時(shí)也去執(zhí)行woker函數(shù),同樣先輸出一條日志waiting for redis ready....,當(dāng)執(zhí)行到event.wait時(shí),這個(gè)event對(duì)象的信號(hào)標(biāo)志位依舊為False,所以執(zhí)行到這里的時(shí)候,threading-2也會(huì)被阻塞。?
過(guò)了3秒后,MainThread主線程sleep結(jié)束,開(kāi)始向下運(yùn)行,執(zhí)行了redis_ready.set()后,我們創(chuàng)建的那個(gè)名為redis_ready的event對(duì)象中的信號(hào)標(biāo)志會(huì)變?yōu)門(mén)rue,當(dāng)這event對(duì)象的信號(hào)標(biāo)志變?yōu)門(mén)rue之后,之前阻塞的threading-1和threading-2都會(huì)被喚醒,繼續(xù)執(zhí)行woker函數(shù)后面的代碼。?
(threading-1) redis ready,and connect to redis server and do some work Sun May 14 09:35:46 2017?
(threading-2) redis ready,and connect to redis server and do some work Sun May 14 09:35:46 2017?
四、event對(duì)象的補(bǔ)充。?
threading.Event的wait方法還接受一個(gè)超時(shí)參數(shù),默認(rèn)情況下如果事件一致沒(méi)有發(fā)生,wait方法會(huì)一直阻塞下去,而加入這個(gè)超時(shí)參數(shù)之后,如果阻塞時(shí)間超過(guò)這個(gè)參數(shù)設(shè)定的值之后,wait方法會(huì)返回。對(duì)應(yīng)于上面的應(yīng)用場(chǎng)景,如果Redis服務(wù)器一致沒(méi)有啟動(dòng),我們希望子線程能夠打印一些日志來(lái)不斷地提醒我們當(dāng)前沒(méi)有一個(gè)可以連接的Redis服務(wù),我們就可以通過(guò)設(shè)置這個(gè)超時(shí)參數(shù)來(lái)達(dá)成這樣的目的:
云專(zhuān)線服務(wù),包括外部專(zhuān)線和跨區(qū)域?qū)>€兩種,用戶可根據(jù)實(shí)際情況進(jìn)行選擇。通過(guò)專(zhuān)線服務(wù),可以在用戶的專(zhuān)用數(shù)據(jù)中心和云專(zhuān)線之間建立高速、穩(wěn)定、安全的內(nèi)網(wǎng)連接,也可以在云專(zhuān)線的不同區(qū)域之間實(shí)現(xiàn)同一用戶的多用戶內(nèi)網(wǎng)連接。
總結(jié)
以上是生活随笔為你收集整理的python并发入门(part5 event对象)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 05-01-部署 WSUS on Win
- 下一篇: 平安普惠i贷逾期会怎么样