1. 程式人生 > >Python基礎(四)--- Python多執行緒介紹,開啟執行緒的三種方式,time模組,join,Daemon,Lock、Rlock,事件機制,Timer

Python基礎(四)--- Python多執行緒介紹,開啟執行緒的三種方式,time模組,join,Daemon,Lock、Rlock,事件機制,Timer

一、多執行緒介紹
---------------------------------------------------------
    1.threading用於提供執行緒相關的操作,執行緒是應用程式中工作的最小單元。
    2.python當前版本的多執行緒庫沒有實現優先順序、執行緒組,執行緒也不能被停止、暫停、恢復、中斷。

    3.threading模組提供的類:
        Thread, Lock, Rlock, Condition, [Bounded]Semaphore, Event, Timer, local。

    4.threading 模組提供的常用方法:
        threading.currentThread(): 返回當前的執行緒變數。
        threading.enumerate(): 返回一個包含正在執行的執行緒的list。正在執行指執行緒啟動後、結束前,不包括啟動前和終止後的執行緒。
        threading.activeCount(): 返回正在執行的執行緒數量,與len(threading.enumerate())有相同的結果。

    5.threading 模組提供的常量:
        threading.TIMEOUT_MAX 設定threading全域性超時時間。


二、開啟執行緒的三種方式
------------------------------------------------
    1.[方式一:通過低階api建立]
        # -*- encoding=utf-8 -*-

        # 導包
        import threading        #高階執行緒介面
        import time
        import _thread          #低階執行緒介面

        #定義函式
        def hello(str1,str2):
            time.sleep(2)
            #獲取當前執行緒名稱
            print("當前執行緒name:" + threading.currentThread().getName())
            print("hello: " + str1 + ":" + str2)

        # # 開啟執行緒方式1 -- 低階介面方式
        # try:
        #     _thread.start_new(hello,('tom','cat'));
        #     while 1:
        #         pass;
        # except Exception as e :
        #     print("發生異常:" + e)

    2.[方式二:高階api建立]
        try:
            #定義執行緒
            for i in (1,2,3):
                t = threading.Thread(target = hello, args = ('tom','cat'))
                #執行執行緒
                t.start()
        except Exception as e :
            print("發生異常:" + e)

    3.[方式三:通過類建立]
        try:
            # 定義執行緒類
            class MyThread(threading.Thread):
                def __init__(self,arg1,arg2):
                    super(MyThread, self).__init__()    #注意:一定要顯式的呼叫父類的初始化函式。
                    self.arg1=arg1
                    self.arg2=arg2
                def run(self):  #定義每個執行緒要執行的函式
                    time.sleep(1)
                    hello(self.arg1,self.arg2)

            # 開啟執行緒
            t = MyThread("tom","cat")
            t.start()

        except Exception as e :
            print("發生異常:" + e)

三、time模組
--------------------------------------------------------
    import time
    //提取秒,精確到微秒.
    cc = int(time.time() * 1000)        #時間戳 轉換成毫秒.
    cc = time.ctime()                   #日期date
    print(cc)


四、引數
---------------------------------------------------------
    1.後臺執行緒
        t = MyThread("tom","cat")
        t.setDaemon(True)   #設定執行緒為後臺執行緒

    2.阻塞執行緒join
        # join()阻塞當前上下文環境的執行緒,直到呼叫此方法的執行緒終止或到達指定的timeout,
        # 即使設定了setDeamon(True)主執行緒依然要等待子執行緒結束。
        t = MyThread("tom","cat")
        t.join()

    3.設定執行緒名稱
        t = MyThread("tom","cat")
        t.setName("thread--10")


五、Lock、Rlock
----------------------------------------------------------
    1.由於執行緒之間隨機排程:某執行緒可能在執行n條後,CPU接著執行其他執行緒。為了多個執行緒同時操作一個記憶體中的資源時不產生混亂,我們使用鎖。

    2.Lock(指令鎖)是可用的最低階的同步指令。Lock處於鎖定狀態時,不被特定的執行緒擁有。Lock包含兩種狀態——鎖定和非鎖定,以及兩個基本的方法。
    可以認為Lock有一個鎖定池,當執行緒請求鎖定時,將執行緒至於池中,直到獲得鎖定後出池。池中的執行緒處於狀態圖中的同步阻塞狀態。

    3.RLock(可重入鎖)是一個可以被同一個執行緒請求多次的同步指令。RLock使用了“擁有的執行緒”和“遞迴等級”的概念,處於鎖定狀態時,RLock被某個執行緒擁有。擁有RLock的執行緒可以再次呼叫acquire(),釋放鎖時需要呼叫release()相同次數。
    可以認為RLock包含一個鎖定池和一個初始值為0的計數器,每次成功呼叫 acquire()/release(),計數器將+1/-1,為0時鎖處於未鎖定狀態。

    4.簡言之:Lock屬於全域性,Rlock屬於執行緒。
        構造方法:
        Lock(),Rlock(),推薦使用Rlock()

    例項方法:
        acquire([timeout]): 嘗試獲得鎖定。使執行緒進入同步阻塞狀態。
        release(): 釋放鎖。使用前執行緒必須已獲得鎖定,否則將丟擲異常。

    5.買票問題分析
        # 票池
        tickets = 100;
        # 執行緒鎖
        lk  = threading.RLock();

        # 取票方法
        def getTicket():
            # 呼叫acquire([timeout])時,執行緒將一直阻塞,
            # 直到獲得鎖定或者直到timeout秒後(timeout引數可選)。
            # 返回是否獲得鎖。
            lk.acquire();
            global tickets
            tmp = 0;
            if tickets > 0 :
                tmp = tickets;
                tickets -= 1;
            else:
                tmp = 0;
            lk.release();
            return tmp;     # 返回剩餘票數


        class Saler(threading.Thread):

            def run(self):
                while True:
                    tick = getTicket();
                    if tick != 0 :
                        print(self.getName() + ":" + str(tick))
                    else:
                        return ;

        s1 = Saler()
        s2 = Saler()

        s1.start()
        s2.start()


六、事件機制
---------------------------------------------------------
    1.Event(事件)是最簡單的執行緒通訊機制之一:一個執行緒通知事件,其他執行緒等待事件。Event內建了一個初始為False的標誌,當呼叫set()時設為True,呼叫clear()時重置為 False。wait()將阻塞執行緒至等待阻塞狀態。

    2.Event其實就是一個簡化版的 Condition。Event沒有鎖,無法使執行緒進入同步阻塞狀態。

    3.構造方法:
        Event()

    4.例項方法:
        isSet(): 當內建標誌為True時返回True。
        set(): 將標誌設為True,並通知所有處於等待阻塞狀態的執行緒恢復執行狀態。
        clear(): 將標誌設為False。
        wait([timeout]): 如果標誌為True將立即返回,否則阻塞執行緒至等待阻塞狀態,等待其他執行緒呼叫set()。

    5.演示
        # 定義一個事件
        event = threading.Event()

        def func():
            # 等待事件,進入等待阻塞狀態
            print(threading.currentThread().getName() + '執行緒等待event的執行...')

            event.wait()            # 一直等待,直到收到event

            # 收到事件後進入執行狀態
            print (threading.currentThread().getName() +'執行緒收到事件,開始執行執行緒...')

        t1 = threading.Thread(target = func)
        t2 = threading.Thread(target = func)
        t1.start()
        t2.start()

        time.sleep(2)

        # 傳送事件通知
        print('主執行緒發起事件')
        event.set()

        ============結果====================
        Thread-1執行緒等待event的執行...
        Thread-2執行緒等待event的執行...
        [wait 2s]
        主執行緒發起事件
        Thread-1執行緒收到事件,開始執行執行緒...
        Thread-2執行緒收到事件,開始執行執行緒...


七、Timer
---------------------------------------------------------------
    1.Timer(定時器)是Thread的派生類,用於在指定時間後呼叫一個方法。

    2.構造方法:
        Timer(interval, function, args=[], kwargs={})
            interval: 指定的時間
            function: 要執行的方法
            args/kwargs: 方法的引數

    3.例項方法:
        Timer從Thread派生,沒有增加例項方法。

    4.演示
        def func():
            print('定時炸彈爆炸啦~')

        # 新建一個定時器,5秒後執行func方法
        timer = threading.Timer(5,func);
        # 開始計時
        timer.start()