1. 程式人生 > 程式設計 >Python執行緒threading模組用法詳解

Python執行緒threading模組用法詳解

本文例項講述了Python執行緒threading模組用法。分享給大家供大家參考,具體如下:

threading-更高級別的執行緒介面

原始碼:Lib/threading.py
該模組在較低級別thread模組之上構建更高級別的執行緒介面。另請參見mutex和Queue模組。

該dummy_threading模組適用於threading因thread缺失而無法使用的情況 。

注意: 從Python 2.6開始,該模組提供 符合 PEP 8的別名和屬性,以替換camelCase受Java的執行緒API啟發的名稱。此更新的API與multiprocessing模組的API相容 。但是,沒有為camelCase名稱的棄用設定計劃,它們在Python 2.x和3.x中仍然完全受支援。


注意 :從Python 2.5開始,幾個Thread方法引發RuntimeError 而不是AssertionError錯誤地呼叫。

該模組定義了以下功能和物件:

threading.active_count()
threading.activeCount()
返回Thread當前活動的物件數。返回的計數等於返回的列表的長度enumerate()。

在2.6版中更改:添加了active_count()拼寫。

threading.Condition()
返回新條件變數物件的工廠函式。條件變數允許一個或多個執行緒等待,直到另一個執行緒通知它們。

請參閱條件物件。

threading.current_thread()


threading.currentThread()
返回當前Thread物件,對應於呼叫者的控制執行緒。如果未通過threading模組建立呼叫者的控制 執行緒,則返回具有有限功能的虛擬執行緒物件。

在2.6版中更改:添加了current_thread()拼寫。

threading.enumerate()
返回Thread當前活動的所有物件的列表。該列表包括守護執行緒,由其建立的虛擬執行緒物件 current_thread()和主執行緒。它排除了尚未啟動的已終止執行緒和執行緒。

threading.Event()
返回新事件物件的工廠函式。事件管理一個標誌,該標誌可以使用該set()方法設定為true,並使用該方法重置為false clear()。該wait()方法將阻塞,直到該標誌為真。

請參閱事件物件。

類threading.local
表示執行緒區域性資料的類。執行緒區域性資料是其值是執行緒特定的資料。要管理執行緒本地資料,只需建立一個local(或子類)例項並在其上儲存屬性:

mydata = threading.local()
mydata.x = 1

對於單獨的執行緒,例項的值將不同。

有關更多詳細資訊和大量示例,請參閱_threading_local模組的文件字串 。

版本2.4中的新功能。

threading.Lock()
返回新原始鎖定物件的工廠函式。一旦執行緒獲得它,後續嘗試獲取它就會阻塞,直到它被釋放; 任何執行緒都可以釋放它。

請參見鎖定物件。

threading.RLock()
返回新的可重入鎖定物件的工廠函式。必須由獲取它的執行緒釋放重入鎖。一旦執行緒獲得了可重入鎖,同一個執行緒可以再次獲取它而不會阻塞; 執行緒必須在每次獲取它時釋放一次。

請參閱RLock物件。

threading.Semaphore([ 值] )
返回新訊號量物件的工廠函式。訊號量管理一個計數器,表示release()呼叫數減去acquire()呼叫數 加上初始值。該acquire()方法在必要時阻止,直到它可以返回而不使計數器為負。如果沒有給出,則值預設為1。

請參見訊號量物件。

threading.BoundedSemaphore([ 值] )
返回新的有界訊號量物件的工廠函式。有界訊號量檢查以確保其當前值不超過其初始值。如果確實如此,ValueError則被提出。在大多數情況下,訊號量用於保護容量有限的資源。如果訊號量被釋放太多次,則表明存在錯誤。如果沒有給出,則值預設為1。

類 threading.Thread
表示控制執行緒的類。該類可以以有限的方式安全地進行子類化。

請參見執行緒物件。

類 threading.Timer
在指定的時間間隔過後執行函式的執行緒。

見Timer物件。

threading.settrace(func )
為從threading模組啟動的所有執行緒設定跟蹤功能。在呼叫sys.settrace()其run()方法之前,將為每個執行緒 傳遞 func。

版本2.3中的新功能。

threading.setprofile(func )
為從threading模組啟動的所有執行緒設定配置檔案功能。在呼叫sys.setprofile()其run()方法之前,將為每個執行緒 傳遞 func。

版本2.3中的新功能。

threading.stack_size([ 大小] )
返回建立新執行緒時使用的執行緒堆疊大小。可選的 size引數指定用於後續建立的執行緒的堆疊大小,並且必須為0(使用平臺或已配置的預設值)或至少為32,768(32 KiB)的正整數值。如果未指定size,則使用0。如果不支援更改執行緒堆疊大小,ThreadError則引發a。如果指定的堆疊大小無效,則aValueError被提升,堆疊大小未經修改。32kB是目前支援的最小堆疊大小值,以保證直譯器本身有足夠的堆疊空間。請注意,某些平臺可能對堆疊大小的值有特定限制,例如要求最小堆疊大小> 32kB或需要以系統記憶體頁面大小的倍數進行分配 - 應提供平臺文件以獲取更多資訊(4kB頁面是常見的;在沒有更具體的資訊的情況下,建議的方法是使用4096的倍數作為堆疊大小。可用性:Windows,具有POSIX執行緒的系統。

2.5版中的新功能。

異常threading.ThreadError
針對各種與執行緒相關的錯誤提出,如下所述。請注意,許多介面使用RuntimeError而不是ThreadError。

下面記錄了物件的詳細介面。

該模組的設計基於Java的執行緒模型。但是,在Java使鎖和條件變數成為每個物件的基本行為的地方,它們是Python中的獨立物件。Python的Thread類支援Java的Thread類的行為的子集; 目前,沒有優先順序,沒有執行緒組,執行緒不能被銷燬,停止,暫停,恢復或中斷。Java的Thread類的靜態方法在實現時會對映到模組級函式。

下面描述的所有方法都是原子執行的。

執行緒物件

此類表示在單獨的控制執行緒中執行的活動。有兩種方法可以指定活動:將可呼叫物件傳遞給建構函式,或者通過覆蓋run()子類中的方法。不應在子類中重寫其他方法(建構函式除外)。換句話說, 只 覆蓋此類的init()和run()方法。

建立執行緒物件後,必須通過呼叫執行緒的start()方法啟動其活動。這將run()在單獨的控制執行緒中呼叫該方法。

一旦執行緒的活動開始,執行緒就被認為是“活著的”。當它的run()方法終止時,它會停止活動- 通常,或者通過引發未處理的異常。該is_alive()方法測試執行緒是否存活。

其他執行緒可以呼叫執行緒的join()方法。這會阻塞呼叫執行緒,直到呼叫其join()方法的執行緒終止。

執行緒有一個名字。名稱可以傳遞給建構函式,並通過name屬性讀取或更改。

執行緒可以標記為“守護程式執行緒”。這個標誌的意義在於當只剩下守護程序執行緒時整個Python程式退出。初始值繼承自建立執行緒。可以通過daemon酒店設定標誌。

注意:守護程式執行緒在關閉時突然停止。他們的資源(例如開啟檔案,資料庫事務等)可能無法正確釋出。如果您希望執行緒正常停止,請使它們成為非守護程序並使用合適的信令機制,例如Event。

有一個“主執行緒”物件; 這對應於Python程式中的初始控制執行緒。它不是守護程式執行緒。

有可能建立“虛擬執行緒物件”。這些是與“外部執行緒”相對應的執行緒物件,它們是線上程模組外部啟動的控制執行緒,例如直接來自C程式碼。虛擬執行緒物件具有有限的功能; 他們總是被認為是活著的和守護的,不能被join()編輯。它們永遠不會被刪除,因為無法檢測外來執行緒的終止。

class threading.Thread(group = None,target = None,name = None,args =(),kwargs = {} )
應始終使用關鍵字引數呼叫此建構函式。引數是:

小組應該None; 在實現ThreadGroup類時為將來的擴充套件保留 。

target是run()方法呼叫的可呼叫物件。預設為None,意味著什麼都沒有被呼叫。

name是執行緒名稱。預設情況下,唯一名稱由“Thread- N ” 形式構成,其中N是小十進位制數。

args是目標呼叫的引數元組。預設為()。

kwargs是目標呼叫的關鍵字引數字典。預設為{}。

如果子類重寫建構函式,則必須確保Thread.init()在對執行緒執行任何其他操作之前呼叫基類建構函式()。
start()
開始執行緒的活動。

每個執行緒物件最多隻能呼叫一次。它安排run()在單獨的控制執行緒中呼叫物件的方法。

此方法將RuntimeError在同一個執行緒物件上多次呼叫if。

run()
表示執行緒活動的方法。

您可以在子類中重寫此方法。標準run() 方法呼叫傳遞給物件建構函式的可呼叫物件作為目標引數(如果有),分別使用args和kwargs引數中的順序和關鍵字引數。

join([ 超時] )
等到執行緒終止。這將阻塞呼叫執行緒,直到呼叫其join()方法的執行緒終止 - 正常或通過未處理的異常 - 或直到發生可選的超時。

當超時引數存在而不存在時None,它應該是一個浮點數,指定操作的超時(以秒為單位)(或其中的分數)。由於join()總是返回None,必須呼叫isAlive()後join()決定超時是否發生了-如果執行緒還活著時,join()呼叫超時。

當timeout引數不存在時None,操作將阻塞,直到執行緒終止。

執行緒可以join()多次編輯。

join()提出了RuntimeError如果試圖加入當前執行緒因為這將導致死鎖。join()線上程啟動之前它也是一個錯誤, 並且嘗試這樣做會引發相同的異常。

name
字串僅用於識別目的。它沒有語義。多個執行緒可以賦予相同的名稱。初始名稱由建構函式設定。

版本2.6中的新功能。

getName()
setName()
適用於2.6之前的API name。

ident
此執行緒的“執行緒識別符號”或者None執行緒尚未啟動。這是一個非零整數。看 thread.get_ident()功能。當執行緒退出並建立另一個執行緒時,可以回收執行緒識別符號。即使線上程退出後,該識別符號也可用。

版本2.6中的新功能。

is_alive()
isAlive()
返回執行緒是否存活。

此方法True在run()方法啟動之前返回,直到run()方法終止之後。模組函式 enumerate()返回所有活動執行緒的列表。

在2.6版中更改:添加了is_alive()拼寫。

daemon
一個布林值,指示此執行緒是否為守護程式執行緒(True)或不是(False)。必須在start()呼叫之前設定,否則RuntimeError引發。它的初始值繼承自建立執行緒; 主執行緒不是守護程式執行緒,因此在主執行緒中建立的所有執行緒都預設為daemon = False。

當沒有剩下活著的非守護程序執行緒時,整個Python程式退出。

版本2.6中的新功能。

isDaemon(
setDaemon()
適用於2.6之前的API daemon。

鎖定物件

原始鎖是一種同步原語,在鎖定時不屬於特定執行緒。在Python中,它是目前可用的最低階同步原語,由thread 擴充套件模組直接實現。

原始鎖定處於“鎖定”或“解鎖”兩種狀態之一。它是在解鎖狀態下建立的。它有兩種基本方法,acquire()和 release()。當狀態解鎖時,acquire()將狀態更改為鎖定並立即返回。當狀態被鎖定時,acquire() 阻塞直到release()另一個執行緒中的呼叫將其更改為解鎖,然後該acquire()呼叫將其重置為已鎖定並返回。該 release()方法只應在鎖定狀態下呼叫; 它將狀態更改為已解鎖並立即返回。如果嘗試釋放未鎖定的鎖,ThreadError則會引發a。

當acquire()等待狀態轉為解鎖時阻塞多個執行緒時,只有一個執行緒在release()呼叫重置狀態解鎖時繼續; 哪個等待執行緒繼續進行未定義,並且可能因實現而異。

所有方法都以原子方式執行。

Lock.acquire([ 阻止] )
獲取鎖定,阻止或非阻止。

當阻塞引數設定為True(預設值)時呼叫,阻塞直到解鎖,然後將其設定為鎖定並返回True。

在使用阻塞引數設定為的情況下呼叫時False,請勿阻止。如果一個帶阻塞的呼叫設定為True阻塞,則False 立即返回; 否則,將鎖定設定為鎖定並返回True。

Lock.release()
解鎖。

鎖定鎖定後,將其重置為解鎖狀態,然後返回。如果阻止任何其他執行緒等待鎖解鎖,則只允許其中一個繼續執行。

在未鎖定的鎖上呼叫時,ThreadError會引發a。

沒有回報價值。

RLock物件

可重入鎖是同步原語,可以由同一執行緒多次獲取。在內部,除了原始鎖使用的鎖定/解鎖狀態之外,它還使用“擁有執行緒”和“遞迴級別”的概念。在鎖定狀態下,某些執行緒擁有鎖; 在解鎖狀態下,沒有執行緒擁有它。

要鎖定鎖,執行緒會呼叫其acquire()方法; 一旦執行緒擁有鎖,它就會返回。要解鎖鎖,執行緒會呼叫其 release()方法。acquire()/ release()call對可以巢狀; 只有最後一個release()(release()最外面的一對)重置鎖才能解鎖並允許另一個被阻塞的執行緒 acquire()繼續進行。

RLock.acquire([ blocking = 1 ] )
獲取鎖定,阻止或非阻止。

在不帶引數的情況下呼叫:如果此執行緒已擁有鎖,則將遞迴級別遞增1,並立即返回。否則,如果另一個執行緒擁有該鎖,則阻塞直到鎖被解鎖。鎖解鎖後(不屬於任何執行緒),然後獲取所有權,將遞迴級別設定為1,然後返回。如果多個執行緒被阻塞等待鎖解鎖,則一次只能有一個執行緒獲取鎖的所有權。在這種情況下沒有返回值。

在將blocking引數設定為true的情況下呼叫時,執行與不帶引數呼叫時相同的操作,並返回true。

在將blocking引數設定為false的情況下呼叫時,請勿阻止。如果沒有引數的呼叫會阻塞,則立即返回false; 否則,執行與不帶引數呼叫時相同的操作,並返回true。

RLock.release()
釋放鎖定,遞減遞迴級別。如果在遞減之後它為零,則將鎖重置為未鎖定(不由任何執行緒擁有),並且如果阻止任何其他執行緒等待鎖解鎖,則允許其中一個繼續進行。如果在遞減之後遞迴級別仍然非零,則鎖保持鎖定並由呼叫執行緒擁有。

僅在呼叫執行緒擁有鎖時呼叫此方法。RuntimeError如果在鎖定解鎖時呼叫此方法,則引發A.

沒有回報價值。

條件物件

條件變數總是與某種鎖相關聯; 這可以傳入,或者預設建立一個。(當多個條件變數必須共享同一個鎖時,傳入一個是有用的。)

條件變數具有acquire()與release()該呼叫相關聯的鎖的相應方法的方法。它還有一種wait() 方法notify()和notifyAll()方法。只有在呼叫執行緒獲得鎖定時才呼叫這三個,否則 RuntimeError引發a。

該wait()方法釋放鎖,然後阻塞,直到它被另一個執行緒中的相同條件變數喚醒notify()或notifyAll()呼叫。一旦被喚醒,它就會重新獲得鎖並返回。也可以指定超時。

該notify()方法喚醒等待條件變數的其中一個執行緒,如果有的話正在等待。該notifyAll()方法喚醒等待條件變數的所有執行緒。

注意:notify()和notifyAll()方法不釋放鎖; 這意味著被喚醒的一個或多個執行緒不會wait()立即從它們的呼叫返回,而是僅在呼叫notify()或notifyAll()最終放棄鎖的所有權的執行緒時 返回 。

提示:使用條件變數的典型程式設計風格使用鎖來同步對某些共享狀態的訪問; 對狀態的特定變化感興趣的執行緒wait()重複呼叫,直到它們看到所需的狀態,而執行緒修改狀態呼叫notify()或者 notifyAll()當它們改變狀態時它可能是其中一個服務員的期望狀態。例如,以下程式碼是具有無限緩衝區容量的通用生產者 - 消費者情況:

# Consume one item
cv.acquire()
while not an_item_is_available():
  cv.wait()
get_an_available_item()
cv.release()

# Produce one item
cv.acquire()
make_an_item_available()
cv.notify()
cv.release()

要在notify()和之間進行選擇notifyAll(),請考慮一個狀態更改是否只對一個或多個等待執行緒感興趣。例如,在典型的生產者 - 消費者情況下,向緩衝區新增一個專案只需要喚醒一個消費者執行緒。

class threading.Condition([ lock ] )
如果給出了lock引數None,則它必須是一個Lock 或RLock物件,並且它被用作底層鎖。否則,將RLock建立一個新物件並將其用作基礎鎖。

acquire(* args )
獲取底層鎖。此方法在底層鎖上呼叫相應的方法; 返回值是該方法返回的任何值。

release()
釋放底層鎖。此方法在底層鎖上呼叫相應的方法; 沒有回報價值。

wait([ 超時] )
等到通知或直到發生超時。如果在呼叫此方法時呼叫執行緒尚未獲取鎖定,RuntimeError則引發a。

此方法釋放底層鎖,然後阻塞,直到它被另一個執行緒中的相同條件變數喚醒notify()或notifyAll()呼叫,或者直到發生可選超時。一旦被喚醒或超時,它就會重新獲得鎖定並返回。

當超時引數存在而不存在時None,它應該是一個浮點數,指定操作的超時(以秒為單位)(或其中的分數)。

當底層鎖是a時RLock,它不會使用其release()方法釋放,因為當遞迴多次獲取鎖時,這實際上可能無法解鎖。相反,使用了RLock類的內部介面,即使多次遞迴獲取它也能真正解鎖它。然後,在重新獲取鎖時,使用另一個內部介面來恢復遞迴級別。

notify(n = 1 )
預設情況下,喚醒一個等待此條件的執行緒(如果有)。如果在呼叫此方法時呼叫執行緒尚未獲取鎖定, RuntimeError則引發a。

此方法最多喚醒等待條件變數的n個執行緒; 如果沒有執行緒在等待,那麼這是一個無操作。

如果至少有n個 執行緒在等待,那麼當前的實現只會喚醒n 個執行緒。但是,依靠這種行為是不安全的。未來的優化實現有時可能會喚醒超過 n個執行緒。

注意:喚醒執行緒實際上不會從其wait() 呼叫返回,直到它可以重新獲取鎖定。由於notify()不釋放鎖,其呼叫者應該。

notify_all()
notifyAll()
喚醒等待這種情況的所有執行緒。這種方法就像 notify(),但喚醒所有等待的執行緒而不是一個。如果在呼叫此方法時呼叫執行緒尚未獲取鎖定, RuntimeError則引發a。

在2.6版中更改:添加了notify_all()拼寫。

訊號量物件

這是電腦科學史上最古老的同步原語之一,由早期的荷蘭電腦科學家Edsger W. Dijkstra(他使用P()而V()不是acquire()和release())發明。

訊號量管理一個內部計數器,該計數器按每次acquire()呼叫遞減並按每次 呼叫遞增release()。計數器永遠不會低於零; 當acquire()發現它為零時,它會阻塞,等待其他執行緒呼叫release()。

class threading.Semaphore([ value ] )
可選引數給出內部計數器的初始值 ; 它預設為1。如果給定的值小於0,ValueError則引發。

acquire([ 阻止] )
獲取訊號量。

在不帶引數的情況下呼叫:如果內部計數器在輸入時大於零,則將其減1並立即返回。如果在進入時為零,則阻塞,等待其他執行緒呼叫 release()以使其大於零。這是通過適當的互鎖來完成的,這樣如果多個acquire()呼叫被阻止,它們 release()將完全喚醒其中一個。實現可以隨機選擇一個,因此不應該依賴被阻塞的執行緒被喚醒的順序。在這種情況下沒有返回值。

當使用blocking設定為true 呼叫時,執行與不帶引數呼叫時相同的操作,並返回true。

當阻塞設定為false 時呼叫,請勿阻止。如果沒有引數的呼叫會阻塞,則立即返回false; 否則,執行與不帶引數呼叫時相同的操作,並返回true。

release()
釋放訊號量,將內部計數器遞增1。當它在進入時為零並且另一個執行緒正在等待它再次大於零時,喚醒該執行緒。

Semaphore示例

訊號量通常用於保護容量有限的資源,例如資料庫伺服器。在資源大小固定的任何情況下,您應該使用有界訊號量。在產生任何工作執行緒之前,您的主執行緒將初始化訊號量:

maxconnections = 5
...
pool_sema = BoundedSemaphore(value=maxconnections)

一旦產生,工作執行緒在需要連線到伺服器時呼叫訊號量的獲取和釋放方法:

pool_sema.acquire()
conn = connectdb()
... use connection ...
conn.close()
pool_sema.release()

有界訊號量的使用減少了導致訊號量被釋放的程式設計錯誤超過其獲取的程式設計錯誤的可能性。

事件物件

這是執行緒之間通訊的最簡單機制之一:一個執行緒發出事件訊號,其他執行緒等待它。

事件物件管理一個內部標誌,該標誌可以使用該set()方法設定為true,並使用該 方法重置為false clear() 。該wait()方法將阻塞,直到該標誌為真。

類threading.Event
內部標誌最初是假的。

is_set()
isSet()
當且僅當內部標誌為真時返回true。

在2.6版中更改:添加了is_set()拼寫。

set()
將內部標誌設定為true。等待它變為真的所有執行緒都被喚醒。wait()一旦標誌為真,呼叫的執行緒將不會阻塞。

clear()
將內部標誌重置為false。隨後,執行緒呼叫 wait()將阻塞,直到set()被呼叫以再次將內部標誌設定為true。

wait([ 超時] )
阻止,直到內部標誌為真。如果輸入時內部標誌為真,則立即返回。否則,阻塞直到另一個執行緒呼叫 set()將標誌設定為true,或者直到發生可選的超時。

當超時引數存在而不存在時None,它應該是一個浮點數,指定操作的超時(以秒為單位)(或其中的分數)。

此方法在退出時返回內部標誌,因此它將始終返回, True除非給出超時並且操作超時。

在2.7版中更改:以前,該方法始終返回None。

定時器物件

此類表示應該在經過一定時間後執行的操作 - 計時器。 Timer是一個子類,Thread 因此也可以作為建立自定義執行緒的示例。

通過呼叫start() 方法,啟動計時器,就像使用執行緒一樣。通過呼叫cancel()方法可以停止計時器(在其動作開始之前) 。計時器在執行其操作之前將等待的時間間隔可能與使用者指定的時間間隔不完全相同。

例如:

def hello():
  print "hello,world"

t = Timer(30.0,hello)
t.start() # after 30 seconds,"hello,world" will be printed

class threading.Timer(interval,function,args = [],kwargs = {} )
建立一個計時器,在經過間隔秒後,將使用引數args和關鍵字引數kwargs執行函式。

cancel()
停止計時器,取消執行計時器的操作。這隻有在計時器仍處於等待階段時才有效。

在with語句中使用鎖,條件和訊號量

此模組提供的具有acquire()和 release()方法的所有物件都可以用作with 語句的上下文管理器。acquire()進入塊時將呼叫該方法,並release()在退出塊時呼叫該方法。

目前Lock,RLock,Condition, Semaphore,和BoundedSemaphore物件可以用作 with宣告上下文管理。例如:

import threading

some_rlock = threading.RLock()

with some_rlock:
  print "some_rlock is locked while this executes"

線上程程式碼中匯入

雖然匯入機制是執行緒安全的,但由於提供執行緒安全的方式存在固有限制,因此執行緒匯入有兩個主要限制:

  • 首先,除了在主模組中,匯入不應該產生產生新執行緒然後以任何方式等待該執行緒的副作用。如果生成的執行緒直接或間接嘗試匯入模組,則不遵守此限制可能導致死鎖。
  • 其次,所有匯入嘗試必須在直譯器開始關閉之前完成。僅通過從通過執行緒模組建立的非守護程式執行緒執行匯入,可以最容易地實現這一點。直接使用執行緒模組建立的守護程式執行緒和執行緒將需要一些其他形式的同步,以確保在系統關閉開始後它們不會嘗試匯入。不遵守此限制將導致在直譯器關閉期間出現間歇性異常和崩潰(因為後期匯入嘗試訪問不再處於有效狀態的機器)。

更多關於Python相關內容感興趣的讀者可檢視本站專題:《Python程序與執行緒操作技巧總結》、《Python資料結構與演算法教程》、《Python函式使用技巧總結》、《Python字串操作技巧彙總》、《Python入門與進階經典教程》、《Python+MySQL資料庫程式設計入門教程》及《Python常見資料庫操作技巧彙總》

希望本文所述對大家Python程式設計有所幫助。