python基本 -- threading多線程模塊的使用

    python多線程編程,通常使用thread和threading模塊。thread模塊想對較底層,threading模塊對thread模塊進行了封裝,更便於使用。全部,一般多線程編程使用threading模塊。python

(一)threading模塊shell

Thread 線程類,這是咱們用的最多的一個類,你能夠指定線程函數執行或者繼承自它均可以實現子線程功能;
Timer與Thread相似,但要等待一段時間後纔開始運行;
Lock 鎖原語,這個咱們能夠對全局變量互斥時使用;
RLock 可重入鎖,使單線程能夠再次得到已經得到的鎖;
Condition 條件變量,能讓一個線程停下來,等待其餘線程知足某個「條件」;
Event 通用的條件變量。多個線程能夠等待某個事件發生,在事件發生後,全部的線程都被激活;
Semaphore爲等待鎖的線程提供一個相似「等候室」的結構;
BoundedSemaphore 與semaphore相似,但不容許超過初始值;
Queue:實現了多生產者(Producer)、多消費者(Consumer)的隊列,支持鎖原語,可以在多個線程之間提供很好的同步支持。

    (1)threading.Thread類編程

getName(self) 返回線程的名字
isAlive(self) 布爾標誌,表示這個線程是否還在運行中
isDaemon(self) 返回線程的daemon標誌
join(self, timeout=None) 程序掛起,直到線程結束,若是給出timeout,則最多阻塞timeout秒
run(self) 定義線程的功能函數
setDaemon(self, daemonic) 把線程的daemon標誌設爲daemonic
setName(self, name) 設置線程的名字
start(self) 開始線程執行

    (2)threading.Queue類多線程

Queue隊列
LifoQueue後入先出(LIFO)隊列
PriorityQueue 優先隊列

(二)線程的建立函數

    線程的建立通常有兩種:①將建立的函數傳遞進threading.Thread()對象。②繼承threading.Thread類,一般重寫run()方法。ui

    (1)使用threading.Thread(),實例化一個線程線程

# -*- coding: utf-8 -*-
import threading

# 使用threading.Thread(),實例化一個線程
def T():
    print threading.current_thread().getName()

# 建立線程對象
t1 = threading.Thread(target=T, name='tt11')
# 啓動線程
t1.start()
t1.join()

    (2)建立threading.Thread 的子類, 並覆蓋run() 方法code

# -*- coding: utf-8 -*-
import threading

# 建立threading.Thread 的子類, 並覆蓋run() 方法
class T(threading.Thread):
    # 重寫父類run()方法
    def run(self):
        print self.getName()

# 實例化線程,並運行
t1 = T()
t1.start()

    (3)例子對象

# -*- coding: utf-8 -*-
import threading

class T(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        pass


def main():
    t = T()
    t.start()

if __name__ == '__main__':
    main()

    (4)join方法繼承

        用來阻塞上下文,直到該線程結束。

def join(self, timeout=None):
    pass

    (5)setDaemon方法

守護線程    
當咱們在程序運行中,執行一個主線程,若是主線程又建立一個子線程,主線程和子線程就分兵兩路,
當主線程完成想退出時,會檢驗子線程是否完成。若是子線程未完成,則主線程會等待子線程完成後再退出。
可是有時候咱們須要的是,只要主線程完成了,無論子線程是否完成,都要和主線程一塊兒退出,
這時就能夠用setDaemon方法,並設置其參數爲True。

(三)共享資源的訪問

    共享資源,互斥與同步。

    (1)簡單的threading.Lock() 鎖

# -*- coding: utf-8 -*-
import threading

counter = 0
mutex = threading.Lock()


class T(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        # 全局變量
        global counter, mutex
        time.sleep(1)
        # 得到加鎖
        if mutex.acquire():
            counter += 1
            # 釋放鎖
            mutex.release()


def main():
    t = T()
    t.start()

if __name__ == '__main__':
    main()
當一個線程調用Lock對象的acquire()方法得到鎖時,這把鎖就進入「locked」狀態。
由於每次只有一個線程1能夠得到鎖,因此若是此時另外一個線程2試圖得到這個鎖,該線程2就會變爲「blo同步阻塞狀態。
直到擁有鎖的線程1調用鎖的release()方法釋放鎖以後,該鎖進入
「unlocked」狀態。線程調度程序從處於同步阻塞狀態的線程中選擇一個來得到鎖,並使得該線程進入運行(running)狀態。

    (2)可重入鎖 threading.RLock() 

        當線程在得到加鎖以後,又須要共享資源,須要再次加鎖。但...

# -*- coding: utf-8 -*-
import threading

counter = 0
mutex = threading.Lock()
# mutex = threading.RLock()


class T(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        # 全局變量
        global counter, mutex
        time.sleep(1)
        # 得到加鎖
        if mutex.acquire():
            counter += 1
            # 再次加鎖
            if mutex.acquire():
                counter += 1
                mutex.release()
            # 釋放鎖
            mutex.release()


def main():
    t = T()
    t.start()

if __name__ == '__main__':
    main()
此時程序會掛起,也就是造成了最簡單死鎖。
在Python中爲了支持在同一線程中屢次請求同一資源,引入了‘可重入鎖’。
count 記錄了acquire的次數,從而使得資源能夠被屢次require。
直到一個線程全部的acquire都被release,其餘的線程才能得到資源。

# 源代碼
def RLock(*args, **kwargs):
    return _RLock(*args, **kwargs)

class _RLock(_Verbose):

    def __init__(self, verbose=None):
        _Verbose.__init__(self, verbose)
        self.__block = _allocate_lock()
        self.__owner = None
        self.__count = 0

    (3)使用Condition實現複雜的同步

Condition被稱爲條件變量,除了提供與Lock相似的acquire和release方法外,還提供了wait和notify方法。

使用Condition的主要方式爲:
線程首先acquire一個條件變量,而後判斷一些條件。
若是條件不知足則wait;
若是條件知足,進行一些處理改變條件後,經過notify方法通知其餘線程,其餘處於wait狀態的線程接到通知後會從新判斷條件。
不斷的重複這一過程,從而解決複雜的同步問題。

        一個經典的例子。生產者消費者問題。(理解上述,代碼其實很簡單。)

import threading  
import time  
   
condition = threading.Condition()  
products = 0  
   
class Producer(threading.Thread):  
    def __init__(self):  
        threading.Thread.__init__(self)  
          
    def run(self):  
        global condition, products  
        while True:  
            if condition.acquire():  
                if products < 10:  
                    products += 1;  
                    print "Producer(%s):deliver one, now products:%s" %(self.name, products)  
                    condition.notify()  
                else:  
                    print "Producer(%s):already 10, stop deliver, now products:%s" %(self.name, products)  
                    condition.wait();  
                condition.release()  
                time.sleep(2)  
          
class Consumer(threading.Thread):  
    def __init__(self):  
        threading.Thread.__init__(self)  
          
    def run(self):  
        global condition, products  
        while True:  
            if condition.acquire():  
                if products > 1:  
                    products -= 1  
                    print "Consumer(%s):consume one, now products:%s" %(self.name, products)  
                    condition.notify()  
                else:  
                    print "Consumer(%s):only 1, stop consume, products:%s" %(self.name, products)  
                    condition.wait();  
                condition.release()  
                time.sleep(2)  
                  
if __name__ == "__main__":  
    for p in range(0, 2):  
        p = Producer()  
        p.start()  
          
    for c in range(0, 10):  
        c = Consumer()  
        c.start()

    (4)使用 threading.Event 實現線程間通訊

使用threading.Event可使一個線程等待其餘線程的通知,咱們把這個Event傳遞到線程對象中,
Event默認內置了一個標誌,初始值爲False。
一旦該線程經過wait()方法進入等待狀態,直到另外一個線程調用該Event的set()方法將內置標誌設置爲True時,
該Event會通知全部等待狀態的線程恢復運行。
import threading  
import time  
  
class MyThread(threading.Thread):  
    def __init__(self, signal):  
        threading.Thread.__init__(self) 
        # 初始化 
        self.singal = signal  
          
    def run(self):  
        print "I am %s,I will sleep ..."%self.name  
        # 進入等待狀態
        self.singal.wait()  
        print "I am %s, I awake..." %self.name  
          
if __name__ == "__main__":
    # 初始 爲 False 
    singal = threading.Event()  
    for t in range(0, 3):  
        thread = MyThread(singal)  
        thread.start()  
      
    print "main thread sleep 3 seconds... "  
    time.sleep(3)  
    # 喚醒含有signal, 處於等待狀態的線程  
    singal.set()

                                                            -- 2014年08月23日03:53:22

相關文章
相關標籤/搜索