摘要:的類行為是的類行為的子集,目前尚不支持優先級線程組,線程無法銷毀停止暫停恢復或中斷。表示繼承創建該線程的當前線程的屬性。重入鎖,同步原語的一種,可由同一線程多次獲取已持有的鎖。
threading在低級的_thread模塊上構建了更高級的線程接口。
threading模塊基于Java線程模型設計。不過Java中鎖和條件變量是每個對象的基本行為,在python中卻是多帶帶的對象。python的Thread類行為是Java的Thread類行為的子集,目前尚不支持優先級、線程組,線程無法銷毀、停止、暫停、恢復或中斷。Java中Thread類的靜態方法在Python中映射為模塊級的函數。
模塊級函數threading.active_count()
返回當前活動的Thread對象的數量,與enumerate()函數返回的列表元素個數相同
threading.current_thread()
返回當前Thread對象,對應調用者的控制線程(thread of control)。如果調用者的控制線程不是通過threading模塊創建,返回一個功能受限的啞線程對象(dummy thread object)
threading.get_ident()
返回一個非零整數,代表當前線程的"線程標識符"。這個值意在作為魔術cookie使用,例如作為索引從特定于線程的字典對象獲取數據。當一個線程退出,新的線程創建,線程標識符可能被回收使用
threading.enumerate()
返回當前活動Thread對象的列表。該列表包含守護線程、current_thread()函數創建的啞線程,以及主線程,不包含已終止的線程和未啟動的線程。
threading.main_thread()
返回主線程對象。通常來說,主線程就是啟動python解釋器的線程。
threading.settrace(func)
為啟動自threading模塊的所有線程設置一個trace函數。在每個線程的run()方法調用前,傳遞func參數給sys.settrace()
threading.setprofile(func)
為啟動自threading模塊的所有線程設置一個profile函數。在每個線程的run()方法調用前,傳遞func參數給sys.setprofile()
threading.stack_size([size])
返回創建新線程使用的線程堆棧大小。
可選參數size指定后續創建的線程的堆棧大小,必須是0(表示使用平臺或配置的默認值)或大于等于32768(32KiB)的正整數。如果未指定,默認size為0.
如果不支持改動線程堆棧大小,拋出RuntimeError異常。如果size不合法,拋出ValueError異常,堆棧大小保持不變。
32KiB是目前能保證解釋器堆棧空間充足的最小值。某些平臺可能對堆棧大小做了特殊的限制,比如要求最小堆棧大小在32KiB以上,或要求以系統內存頁大小的倍數分配。
Windows系統及使用POSIX線程的系統可用
常量threading.TIMEOUT_MAX
阻塞函數(Lock.acquire(), RLock.acquire(), Condition.wait()等)的timeout參數可接受的最大值。超出該值將拋出OverflowError異常。
Thread-local數據的值是特定于線程的。管理Thread-local數據,只需要創建local或其子類的實例并在該實例上存儲屬性:
mydata = threading.local() mydata.x = 1
不同的線程,實例的值也會不同。
class threading.local表示thread-local數據的類。
ThreadThread類代表在多帶帶的控制線程中運行的活動,有兩種方式指定:傳遞可調用對象到構造器的target參數,或重寫子類的run()方法。除了__int__()方法和run()方法,Thread子類不應該重寫除此之外的其他方法。
創建的線程對象,必須使用start()方法啟動,start()在一個多帶帶的控制線程調用run()方法。這時該線程被認為是"活動的"。當run()方法結束(正常執行完成或拋出了未處理的異常)時,線程對象不再是"活動的"。is_alive()方法可用于檢查線程是否處于活動狀態。
調用線程對象的join()方法將導致線程阻塞,直到調用join()方法的線程執行結束。
線程擁有名字,可以傳遞給構造器。通過name屬性讀取或修改。
主線程:對應python程序的初始控制線程。主線程不是守護線程。
守護線程:當沒有非守護線程處于活動狀態時,整個python程序將退出。通過daemon屬性或構造器參數,可以標記一個線程為守護線程。daemon屬性的初始值繼承自創建該線程的線程
啞線程:對應"外部線程"alien thread,即在threading模塊之外(比如C代碼)啟動的控制線程。啞線程具有有限的功能,總是認為是活動的和守護的,不能調用join()方法。它們永遠不會被刪除,因為不能檢測外部線程的結束情況。
Note:守護線程將在程序關閉時直接停止。相關資源(比如打開的文件、數據庫事務等)可能不會被妥善地釋放。如果想要線程優雅地停止,將線程設置為非守護線程,并使用合適的信號機制比如Event
class threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)group:None。作為將來實現ThreadGroup類后的保留參數。
target:可調用對象,將被run()方法調用
name:線程名稱。默認構建Thread-N形式的唯一名稱。
args:target調用需要接收的位置參數,元組形式
kwargs:target調用需要接收的關鍵字參數,字典形式
daemon:傳遞一個布爾值,標記該線程是否為守護線程。None表示繼承創建該線程的當前線程的daemon屬性。
如果子類繼承Thread并重寫構造器,必須確保在執行線程的其他操作前在構造器中調用Thread.__init__()
start()
開啟線程。每個線程最多只能調用一次,否則拋出RuntimeError異常。它將在一個多帶帶的控制線程調用線程對象的run()方法。
run()
定義線程功能的方法,通常在子類中重寫。標準的run()方法調用傳入構造器的可調用對象target(存在的話),并使用args和kwargs分別作為target的位置參數和關鍵字參數。
# 創建Thread的實例,傳給它一個函數 from threading import Thread from time import sleep, ctime sleep_time = [4, 2] def task(task_tag, sleep_tag): print("task", task_tag, "started at:", ctime()) sleep(sleep_tag) print("task", task_tag, "done at:", ctime()) def main(): print("Main thread started at:", ctime()) threads = [] nloops = range(len(sleep_time)) # [0, 1] for i in nloops: t = Thread(target=task, args=(i, sleep_time[i])) threads.append(t) for i in nloops: threads[i].start() # 啟動線程 for i in nloops: threads[i].join() # 主線程阻塞,直至調用join()方法的線程終止 print("Main thread done at:", ctime()) if __name__ == "__main__": main()
# 派生Thread的子類,并創建子類的實例 from threading import Thread from time import sleep, ctime sleep_time = [4, 2] class MyThread(Thread): # 重寫run()方法 def run(self): print(self.name, "started at:", ctime()) self._target(self._args) print(self.name, "done at:", ctime()) def task(sleep_tag): sleep(sleep_tag) def main(): print("Main thread started at:", ctime()) threads = [] nloops = range(len(sleep_time)) for i in nloops: t = MyThread(target=task, args=sleep_time[i], name=task.__name__ + str(i)) threads.append(t) for i in nloops: threads[i].start() for i in nloops: threads[i].join() print("Main thread done at:", ctime()) if __name__ == "__main__": main()
join(timeout=None)
阻塞主線程直到調用join方法的線程終止(可能是正常執行完成,也可能是拋出了未處理的異常)或達到timeout設定的時間。可多次調用。
timeout:阻塞時間(秒)。如果為None,表示一直阻塞直至調用join方法的線程終止;如果不為None,表示阻塞的時間,達到該時間后,不管調用join()方法的線程是否執行完成,繼續執行主線程或其他啟動的線程。
如果線程調用join()方法可能導致死鎖,或在調用start()之前調用join(),拋出RuntimeError異常。
name
獲取或設置線程名稱。多個線程可能名稱相同,初始值由構造器設置。
ident
線程標識符,如果為None說明該線程未啟動。當一個線程退出,新的線程創建,線程標識符可能被回收使用。即使線程退出,該標識符仍可用。
is_alive()
判斷線程是否處于活動狀態。
daemon
布爾標志,表示這個線程是否是守護線程。必須在調用start()之前設置,否則拋出RuntimeError異常。初始值繼承自創建該線程的線程。主線程不是守護線程,因此在主線程中創建的線程daemon屬性默認值為False
CPython實現細節:在CPython中,由于GIL的原因,一次只有一個線程能夠執行python代碼(即使某些面向性能的庫能克服這個限制???)。想要python程序更好地利用多核機器的計算機資源(計算密集型),建議使用multiprocessing或concurrent.futures.ProcessPoolExecutor。如果是同時運行多個I/O密集型任務,threading仍然不失為一個合適的模塊
Lock原語鎖,是同步原語的一種,當它處于"locked"狀態時不屬于特定線程。在python中,這是目前可用的最低級的同步原語,實現自_thread擴展模塊。
原語鎖有兩種狀態:locked(鎖定)或unlocked(未鎖定)。創建時為未鎖定狀態。
原語鎖有兩種方法:acquire()和release()。當鎖處于未鎖定狀態時,acquire()改變其為鎖定狀態。當鎖處于鎖定狀態時,調用acquire()方法將導致線程阻塞,直到其他線程調用release()釋放鎖。
acquire(blocking=True, timeout=-1)
獲取鎖。成功返回True,獲取返回False。
blocking:默認為True,在獲取到鎖之前阻塞線程;反之即使沒有獲取到鎖也不會阻塞線程。
timeout:指定線程阻塞的最長時間,單位為秒;-1表示無限制等待。當blocking為False時,禁止指定timeout參數
release()
釋放鎖。任何線程都可以調用,不只是獲取了鎖的線程。
鎖更改為未上鎖狀態后,對于調用了acquire()方法而導致阻塞的線程,將由系統決定哪個線程獲取到鎖。
release()方法只能在上鎖狀態調用,否則將拋出RuntimeError異常。
RLock重入鎖,同步原語的一種,可由同一線程多次獲取已持有的鎖。除了原語鎖的上鎖/解鎖狀態,重入鎖還使用了owning thread和recursion level的概念。在上鎖狀態,可能有多個線程擁有鎖;在解鎖狀態,沒有線程擁有鎖。
acquire()/release()必須成對出現,可以嵌套,只有最后一個release(即最外層的release)調用才會最終釋放鎖。
class threading.RLockacquire(blocking=True, timeout=-1)
使用默認參數調用時,如果當前線程已經擁有鎖,增加1次遞歸深度并立即返回;如果是其他線程擁有鎖,阻塞當前線程直到鎖被釋放。一旦鎖釋放(遞歸深度為0,此時鎖不屬于任何線程),各個線程爭奪鎖,并設置遞歸深度為1。
release()
釋放鎖且遞歸深度減1。如果調用后遞歸深度為0,重置鎖為未鎖定狀態(不屬于任何線程),由其他線程爭奪鎖。如果調用后遞歸深度非0,鎖仍為上鎖狀態,屬于當前線程。
只能由已經獲取了鎖的線程調用,否則拋出RuntimeError異常。
Conditioncondition變量總是與某種鎖相聯系:傳入或者默認創建的鎖對象。傳入鎖對象適用于多個condition變量需要共享同一個鎖的場景。鎖是condition對象的一部分,不需要對鎖多帶帶進行追蹤。
condition對象遵循上下文管理協議:使用with語句在封閉塊內獲取關聯的鎖對象,在condition對象上調用acquire和release實際上調用的是關聯鎖的對應方法。
class threading.Condition(lock=None)條件變量允許一個或多個線程等待,直到接收到另一個線程的通知。
lock參數必須是Lock或RLock對象,作為底層的鎖使用。默認使用RLock
acquire(*args)
調用底層lock對象的acquire()方法獲取鎖
release()
調用底層lock對象的release()方法釋放鎖
wait(timeout=None)
釋放鎖并阻塞當前線程直到被另外一個線程調用notify()或notify_all()喚醒,或者達到設置的timeout時間,任意一種情況都將重新獲取鎖并返回。
只能由已獲取到鎖的線程調用,否則拋出RuntimeError異常。
3.2版本前該方法始終返回None,3.2版本開始除非超時會返回False,其他情況都返回True
wait_for(predicate, timeout=None)
阻塞當前線程直到可調用對象predicate返回值為True或bool()判斷為True。
wait_for方法將不斷調用wait()方法直到超時或滿足predicate返回值為True或bool()判斷為True。
返回值為最后一次執行predicate的返回值,如果超時返回False。
只能由已獲取到鎖的線程調用,否則拋出RuntimeError異常。
notify(n=1)
喚醒wait()或wait_for()狀態下的某個線程。只能由已獲取到鎖的線程調用,否則拋出RuntimeError異常。
notify_all()
喚醒wait()或wait_for()狀態下的所有線程。只能由已獲取到鎖的線程調用,否則拋出RuntimeError異常。
notify()和notify_all()并不釋放鎖。意思是調用wait()方法的線程不會立即返回,需要等到調用notify()和notify_all()的線程釋放鎖之后才返回。
# 生產者-消費者模式中Condition的用法 # 消費者: with cv: while not an_item_is_available(): cv.wait() get_an_available_item() # 生產者: with cv: make_an_item_available() cv.notify() # 消費者(使用wait_for改進): with cv: cv.wait_for(an_item_is_available) get_an_available_item()Semaphore Objects
信號量對象管理一個內部計數器,隨著調用acquire()減1,release()調用加1,但一定不會小于0。當調用acquire()時如果計數器等于0將會阻塞線程直到某個線程調用release()方法。支持上下文管理器協議
class threading.Semaphore(value=1)指定初始計數器的信號量,每調用一次release()加1,每調用一次acquire()減1。
acquire(blocking=True, timeout=None)
獲取信號量。
使用默認參數調用時:
1. 如果計數器大于0,減1并立即返回True 2. 如果計數器等于0,阻塞直到某個線程調用release()喚醒,喚醒后計數器減1并返回True
release()
釋放信號量。
邊界信號量,計數器值不能超過設置的最大邊界。常用于限制資源占用的場景比如數據庫連接。
Event Objects事件是最簡單的線程間通信機制。事件對象管理一個內部標志,調用set()時該標志為True,調用clear()時該標志為False,調用wait()時線程阻塞直到標志為True
class threading.Eventis_set()
如果事件標志為True,返回True
set()
設置事件標志為True。將喚醒所有調用了wait()而阻塞的線程。
clear()
重置事件標志為False。將阻塞所有調用了wait()的線程。
wait(timeout=None)
阻塞線程直到事件標志為True或超時。
Timer繼承自Thread,表示經過一定時間后要運行的任務。
class threading.Timer(interval, function, args=None, kwargs=None)創建定時器,在interval時間后運行function任務。
cancel()
終止定時器并結束任務(僅對待執行狀態中的任務有效)。
Python 多線程: threading.local類
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/43274.html
摘要:但現在線程沒有優先級,沒有線程組,不能被銷毀停止暫停開始和打斷。守護線程也會結束,并強行終止整個程序。在中,他是目前可用的最底層的同步原語,由模塊提供。當處于狀態時,方法可以將狀態變為,并立即返回。否則會拋出錯誤。對象實現某些服務的共進退。 Python的threading模塊松散地基于Java的threading模塊。但現在線程沒有優先級,沒有線程組,不能被銷毀、停止、暫停、開始和打...
摘要:而線程則是每秒通過輸出當前進程內所有活躍的線程。如果使用強制手段干掉線程,那么很大幾率出現意想不到的。只是通過來約束這些線程,來決定什么時候開始調度,比方說運行了多少個指令就交出,至于誰奪得花魁,得聽操作系統的。 背景 開工前我就覺得有什么不太對勁,感覺要背鍋。這可不,上班第三天就捅鍋了。 我們有個了不起的后臺程序,可以動態加載模塊,并以線程方式運行,通過這種形式實現插件的功能。而模塊...
摘要:擴展支持多用戶并發訪問與線程池。項目請見初學網絡編程之服務器。不允許超過磁盤配額。該文件是一個使用模塊編寫的線程池類。這一步就做到了線程池的作用。 對MYFTP項目進行升級。擴展支持多用戶并發訪問與線程池。MYFTP項目請見python初學——網絡編程之FTP服務器。 擴展需求 1.在之前開發的FTP基礎上,開發支持多并發的功能2.不能使用SocketServer模塊,必須自己實現多線...
摘要:由于線程是操作系統直接支持的執行單元,因此,高級語言通常都內置多線程的支持,也不例外,并且,的線程是真正的,而不是模擬出來的線程。多任務可以由多進程完成,也可以由一個進程內的多線程完成。是模塊中最重要的類之一,可以使用它來創建線程。 由于線程是操作系統直接支持的執行單元,因此,高級語言通常都內置多線程的支持,Python也不例外,并且,Python的線程是真正的Posix Thread...
閱讀 1776·2021-10-27 14:15
閱讀 3835·2021-10-08 10:12
閱讀 1168·2021-09-22 15:55
閱讀 3230·2021-09-22 15:17
閱讀 834·2021-09-02 15:40
閱讀 1748·2019-08-29 18:33
閱讀 1099·2019-08-29 15:22
閱讀 2355·2019-08-29 11:08