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