<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ### 導航 - [索引](../genindex.xhtml "總目錄") - [模塊](../py-modindex.xhtml "Python 模塊索引") | - [下一頁](multiprocessing.xhtml "multiprocessing --- 基于進程的并行") | - [上一頁](concurrency.xhtml "并發執行") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) ? - zh\_CN 3.7.3 [文檔](../index.xhtml) ? - [Python 標準庫](index.xhtml) ? - [并發執行](concurrency.xhtml) ? - $('.inline-search').show(0); | # [`threading`](#module-threading "threading: Thread-based parallelism.") --- 基于線程的并行 **源代碼:** [Lib/threading.py](https://github.com/python/cpython/tree/3.7/Lib/threading.py) \[https://github.com/python/cpython/tree/3.7/Lib/threading.py\] - - - - - - 這個模塊在較低級的模塊 [`_thread`](_thread.xhtml#module-_thread "_thread: Low-level threading API.") 基礎上建立較高級的線程接口。參見: [`queue`](queue.xhtml#module-queue "queue: A synchronized queue class.") 模塊。 在 3.7 版更改: 這個模塊曾經為可選項,但現在總是可用。 注解 雖然他們沒有在下面列出,這個模塊仍然支持Python 2.x系列的這個模塊下以 `camelCase` (駝峰法)命名的方法和函數。 這個模塊定義了以下函數: `threading.``active_count`()返回當前存活的線程類 [`Thread`](#threading.Thread "threading.Thread") 對象。返回的計數等于 [`enumerate()`](#threading.enumerate "threading.enumerate") 返回的列表長度。 `threading.``current_thread`()返回當前對應調用者的控制線程的 [`Thread`](#threading.Thread "threading.Thread") 對象。如果調用者的控制線程不是利用 [`threading`](#module-threading "threading: Thread-based parallelism.") 創建,會返回一個功能受限的虛擬線程對象。 `threading.``get_ident`()返回當前線程的 “線程標識符”。它是一個非零的整數。它的值沒有直接含義,主要是用作 magic cookie,比如作為含有線程相關數據的字典的索引。線程標識符可能會在線程退出,新線程創建時被復用。 3\.3 新版功能. `threading.``enumerate`()以列表形式返回當前所有存活的 [`Thread`](#threading.Thread "threading.Thread") 對象。 該列表包含守護線程,[`current_thread()`](#threading.current_thread "threading.current_thread") 創建的虛擬線程對象和主線程。它不包含已終結的線程和尚未開始的線程。 `threading.``main_thread`()返回主 [`Thread`](#threading.Thread "threading.Thread") 對象。一般情況下,主線程是Python解釋器開始時創建的線程。 3\.4 新版功能. `threading.``settrace`(*func*)為所有 [`threading`](#module-threading "threading: Thread-based parallelism.") 模塊開始的線程設置追蹤函數。在每個線程的 [`run()`](#threading.Thread.run "threading.Thread.run") 方法被調用前,*func* 會被傳遞給 [`sys.settrace()`](sys.xhtml#sys.settrace "sys.settrace") 。 `threading.``setprofile`(*func*)為所有 [`threading`](#module-threading "threading: Thread-based parallelism.") 模塊開始的線程設置性能測試函數。在每個線程的 [`run()`](#threading.Thread.run "threading.Thread.run") 方法被調用前,*func* 會被傳遞給 [`sys.setprofile()`](sys.xhtml#sys.setprofile "sys.setprofile") 。 `threading.``stack_size`(\[*size*\])返回創建線程時用的堆棧大小。可選參數 *size* 指定之后新建的線程的堆棧大小,而且一定要是0(根據平臺或者默認配置)或者最小是32,768(32KiB)的一個正整數。如果 *size* 沒有指定,默認是0。如果不支持改變線程堆棧大小,會拋出 [`RuntimeError`](exceptions.xhtml#RuntimeError "RuntimeError") 錯誤。如果指定的堆棧大小不合法,會拋出 [`ValueError`](exceptions.xhtml#ValueError "ValueError") 錯誤并且不會修改堆棧大小。32KiB是當前最小的能保證解釋器有足夠堆棧空間的堆棧大小。需要注意的是部分平臺對于堆棧大小會有特定的限制,例如要求大于32KiB的堆棧大小或者需要根據系統內存頁面的整數倍進行分配 - 應當查閱平臺文檔有關詳細信息(4KiB頁面比較普遍,在沒有更具體信息的情況下,建議的方法是使用4096的倍數作為堆棧大小)。 [適用于](intro.xhtml#availability): Windows,具有 POSIX 線程的系統。 這個模塊同時定義了以下常量: `threading.``TIMEOUT_MAX`阻塞函數( [`Lock.acquire()`](#threading.Lock.acquire "threading.Lock.acquire"), [`RLock.acquire()`](#threading.RLock.acquire "threading.RLock.acquire"), [`Condition.wait()`](#threading.Condition.wait "threading.Condition.wait"), ...)中形參 *timeout* 允許的最大值。傳入超過這個值的 timeout 會拋出 [`OverflowError`](exceptions.xhtml#OverflowError "OverflowError") 異常。 3\.2 新版功能. 這個模塊定義了許多類,詳見以下部分。 該模塊的設計基于 Java的線程模型。 但是,在Java里面,鎖和條件變量是每個對象的基礎特性,而在Python里面,這些被獨立成了單獨的對象。 Python 的 [`Thread`](#threading.Thread "threading.Thread") 類只是 Java 的 Thread 類的一個子集;目前還沒有優先級,沒有線程組,線程還不能被銷毀、停止、暫停、恢復或中斷。 Java 的 Thread 類的靜態方法在實現時會映射為模塊級函數。 下列描述的方法都是自動執行的。 ## 線程本地數據 線程本地數據是特定線程的數據。管理線程本地數據,只需要創建一個 [`local`](#threading.local "threading.local") (或者一個子類型)的實例并在實例中儲存屬性: ``` mydata = threading.local() mydata.x = 1 ``` 在不同的線程中,實例的值會不同。 *class* `threading.``local`一個代表線程本地數據的類。 更多相關細節和大量示例,參見 `_threading_local` 模塊的文檔。 ## 線程對象 The [`Thread`](#threading.Thread "threading.Thread") class represents an activity that is run in a separate thread of control. There are two ways to specify the activity: by passing a callable object to the constructor, or by overriding the [`run()`](#threading.Thread.run "threading.Thread.run")method in a subclass. No other methods (except for the constructor) should be overridden in a subclass. In other words, *only* override the `__init__()` and [`run()`](#threading.Thread.run "threading.Thread.run") methods of this class. 當線程對象一但被創建,其活動一定會因調用線程的 [`start()`](#threading.Thread.start "threading.Thread.start") 方法開始。這會在獨立的控制線程調用 [`run()`](#threading.Thread.run "threading.Thread.run") 方法。 一旦線程活動開始,該線程會被認為是 '存活的' 。當它的 [`run()`](#threading.Thread.run "threading.Thread.run") 方法終結了(不管是正常的還是拋出未被處理的異常),就不是'存活的'。 [`is_alive()`](#threading.Thread.is_alive "threading.Thread.is_alive") 方法用于檢查線程是否存活。 其他線程可以調用一個線程的 [`join()`](#threading.Thread.join "threading.Thread.join") 方法。這會阻塞調用該方法的線程,直到被調用 [`join()`](#threading.Thread.join "threading.Thread.join") 方法的線程終結。 線程有名字。名字可以傳遞給構造函數,也可以通過 [`name`](#threading.Thread.name "threading.Thread.name") 屬性讀取或者修改。 一個線程可以被標記成一個 "守護線程" 。這個標志的意義是,只有守護線程都終結,整個Python程序才會退出。初始值繼承于創建線程。這個標志可以通過 [`daemon`](#threading.Thread.daemon "threading.Thread.daemon") 特征屬性或者 *守護* 構造函數參數來設置。 注解 守護線程在程序關閉時會突然關閉。他們的資源(例如已經打開的文檔,數據庫事務等等)可能沒有被正確釋放。如果你想你的線程正常停止,設置他們成為非守護模式并且使用合適的信號機制,例如: [`Event`](#threading.Event "threading.Event")。 有個 "主線程" 對象;這對應Python程序里面初始的控制線程。它不是一個守護線程。 "虛擬線程對象" 是可以被創建的。這些是對應于“外部線程”的線程對象,它們是在線程模塊外部啟動的控制線程,例如直接來自C代碼。虛擬線程對象功能受限;他們總是被認為是存活的和守護模式,不能被 [`join()`](#threading.Thread.join "threading.Thread.join") 。因為無法檢測外來線程的終結,它們永遠不會被刪除。 *class* `threading.``Thread`(*group=None*, *target=None*, *name=None*, *args=()*, *kwargs={}*, *\**, *daemon=None*)調用這個構造函數時,必需帶有關鍵字參數。參數如下: *group* 應該為 `None`;為了日后擴展 `ThreadGroup` 類實現而保留。 *target* 是用于 [`run()`](#threading.Thread.run "threading.Thread.run") 方法調用的可調用對象。默認是 `None`,表示不需要調用任何方法。 *name* 是線程名稱。默認情況下,由 "Thread-*N*" 格式構成一個唯一的名稱,其中 *N* 是小的十進制數。 *args* 是用于調用目標函數的參數元組。默認是 `()`。 *kwargs* 是用于調用目標函數的關鍵字參數字典。默認是 `{}`。 如果不是 `None`,線程將被顯式的設置為 *守護模式*,不管該線程是否是守護模式。如果是 `None` (默認值),線程將繼承當前線程的守護模式屬性。 如果子類型重載了構造函數,它一定要確保在做任何事前,先發起調用基類構造器(`Thread.__init__()`)。 在 3.3 版更改: 加入 *daemon* 參數。 `start`()開始線程活動。 它在一個線程里最多只能被調用一次。它安排對象的 [`run()`](#threading.Thread.run "threading.Thread.run") 方法在一個獨立的控制進程中調用。 如果同一個線程對象中調用這個方法的次數大于一次,會拋出 [`RuntimeError`](exceptions.xhtml#RuntimeError "RuntimeError") 。 `run`()代表線程活動的方法。 你可以在子類型里重載這個方法。 標準的 [`run()`](#threading.Thread.run "threading.Thread.run") 方法會對作為 *target* 參數傳遞給該對象構造器的可調用對象(如果存在)發起調用,并附帶從 *args* 和 *kwargs* 參數分別獲取的位置和關鍵字參數。 `join`(*timeout=None*)等待,直到線程終結。這會阻塞調用這個方法的線程,直到被調用 [`join()`](#threading.Thread.join "threading.Thread.join") 的線程終結 -- 不管是正常終結還是拋出未處理異常 -- 或者直到發生超時,超時選項是可選的。 當 *timeout* 參數存在而且不是 `None` 時,它應該是一個用于指定操作超時的以秒為單位的浮點數(或者分數)。因為 [`join()`](#threading.Thread.join "threading.Thread.join") 總是返回 `None` ,所以你一定要在 [`join()`](#threading.Thread.join "threading.Thread.join") 后調用 [`is_alive()`](#threading.Thread.is_alive "threading.Thread.is_alive") 才能判斷是否發生超時 -- 如果線程仍然存貨,則 [`join()`](#threading.Thread.join "threading.Thread.join") 超時。 當 *timeout* 參數不存在或者是 `None` ,這個操作會阻塞直到線程終結。 一個線程可以被 [`join()`](#threading.Thread.join "threading.Thread.join") 很多次。 如果嘗試加入當前線程會導致死鎖, [`join()`](#threading.Thread.join "threading.Thread.join") 會引起 [`RuntimeError`](exceptions.xhtml#RuntimeError "RuntimeError") 異常。如果嘗試 [`join()`](#threading.Thread.join "threading.Thread.join") 一個尚未開始的線程,也會拋出相同的異常。 `name`只用于識別的字符串。它沒有語義。多個線程可以賦予相同的名稱。 初始名稱由構造函數設置。 `getName`()`setName`()舊的 [`name`](#threading.Thread.name "threading.Thread.name") 取值/設值 API;直接當做特征屬性使用它。 `ident`這個線程的 '線程標識符',如果線程尚未開始則為 `None` 。這是個非零整數。參見 [`get_ident()`](#threading.get_ident "threading.get_ident") 函數。當一個線程退出而另外一個線程被創建,線程標識符會被復用。即使線程退出后,仍可得到標識符。 `is_alive`()返回線程是否存活。 當 [`run()`](#threading.Thread.run "threading.Thread.run") 方法剛開始直到 [`run()`](#threading.Thread.run "threading.Thread.run") 方法剛結束,這個方法返回 `True` 。模塊函數 [`enumerate()`](#threading.enumerate "threading.enumerate") 返回包含所有存活線程的列表。 `daemon`一個表示這個線程是(True)否(False)守護線程的布爾值。一定要在調用 [`start()`](#threading.Thread.start "threading.Thread.start") 前設置好,不然會拋出 [`RuntimeError`](exceptions.xhtml#RuntimeError "RuntimeError") 。初始值繼承于創建線程;主線程不是守護線程,因此主線程創建的所有線程默認都是 [`daemon`](#threading.Thread.daemon "threading.Thread.daemon") = `False`。 當沒有存活的非守護線程時,整個Python程序才會退出。 `isDaemon`()`setDaemon`()舊的 [`name`](#threading.Thread.name "threading.Thread.name") 取值/設值 API;建議直接當做特征屬性使用它。 **CPython implementation detail:** CPython下,因為 [Global Interpreter Lock](../glossary.xhtml#term-global-interpreter-lock),一個時刻只有一個線程可以執行Python代碼(盡管如此,某些性能導向的庫可能會克服這個限制)。如果你想讓你的應用更好的利用多核計算機的計算性能,推薦你使用 [`multiprocessing`](multiprocessing.xhtml#module-multiprocessing "multiprocessing: Process-based parallelism.") 或者 [`concurrent.futures.ProcessPoolExecutor`](concurrent.futures.xhtml#concurrent.futures.ProcessPoolExecutor "concurrent.futures.ProcessPoolExecutor") 。但是如果你想同時運行多個I/O綁定任務,線程仍然是一個合適的模型。 ## 鎖對象 原始鎖是一個在鎖定時不屬于特定線程的同步基元組件。在Python中,它是能用的最低級的同步基元組件,由 [`_thread`](_thread.xhtml#module-_thread "_thread: Low-level threading API.") 擴展模塊直接實現。 原始鎖處于 "鎖定" 或者 "非鎖定" 兩種狀態之一。它被創建時為非鎖定狀態。它有兩個基本方法, [`acquire()`](#threading.Lock.acquire "threading.Lock.acquire") 和 [`release()`](#threading.Lock.release "threading.Lock.release") 。當狀態為非鎖定時, [`acquire()`](#threading.Lock.acquire "threading.Lock.acquire") 將狀態改為 鎖定 并立即返回。當狀態是鎖定時, [`acquire()`](#threading.Lock.acquire "threading.Lock.acquire") 將阻塞至其他線程調用 [`release()`](#threading.Lock.release "threading.Lock.release") 將其改為非鎖定狀態,然后 [`acquire()`](#threading.Lock.acquire "threading.Lock.acquire") 調用重置其為鎖定狀態并返回。 [`release()`](#threading.Lock.release "threading.Lock.release") 只在鎖定狀態下調用; 它將狀態改為非鎖定并立即返回。如果嘗試釋放一個非鎖定的鎖,則會引發 [`RuntimeError`](exceptions.xhtml#RuntimeError "RuntimeError") 異常。 鎖同樣支持 [上下文管理協議](#with-locks)。 當多個線程在 [`acquire()`](#threading.Lock.acquire "threading.Lock.acquire") 等待狀態轉變為未鎖定被阻塞,然后 [`release()`](#threading.Lock.release "threading.Lock.release") 重置狀態為未鎖定時,只有一個線程能繼續執行;至于哪個等待線程繼續執行沒有定義,并且會根據實現而不同。 所有方法都是自動執行的。 *class* `threading.``Lock`實現原始鎖對象的類。一旦一個線程獲得一個鎖,會阻塞隨后嘗試獲得鎖的線程,直到它被釋放;任何線程都可以釋放它。 需要注意的是 `Lock` 其實是一個工廠函數,返回平臺支持的具體鎖類中最有效的版本的實例。 `acquire`(*blocking=True*, *timeout=-1*)可以阻塞或非阻塞地獲得鎖。 當調用時參數 *blocking* 設置為 `True` (缺省值),阻塞直到鎖被釋放,然后將鎖鎖定并返回 `True` 。 在參數 *blocking* 被設置為 `False` 的情況下調用,將不會發生阻塞。如果調用時 *blocking* 設為 `True` 會阻塞,并立即返回 `False` ;否則,將鎖鎖定并返回 `True`。 當浮點型 *timeout* 參數被設置為正值調用時,只要無法獲得鎖,將最多阻塞 *timeout* 設定的秒數。*timeout* 參數被設置為 `-1` 時將無限等待。當 *blocking* 為 false 時,*timeout* 指定的值將被忽略。 如果成功獲得鎖,則返回 `True`,否則返回 `False` (例如發生 *超時* 的時候)。 在 3.2 版更改: 新的 *timeout* 形參。 在 3.2 版更改: 現在如果底層線程實現支持,則可以通過POSIX上的信號中斷鎖的獲取。 `release`()釋放一個鎖。這個方法可以在任何線程中調用,不單指獲得鎖的線程。 當鎖被鎖定,將它重置為未鎖定,并返回。如果其他線程正在等待這個鎖解鎖而被阻塞,只允許其中一個允許。 在未鎖定的鎖調用時,會引發 [`RuntimeError`](exceptions.xhtml#RuntimeError "RuntimeError") 異常。 沒有返回值。 ## 遞歸鎖對象 重入鎖是一個可以被同一個線程多次獲取的同步基元組件。在內部,它在基元鎖的鎖定/非鎖定狀態上附加了 "所屬線程" 和 "遞歸等級" 的概念。在鎖定狀態下,某些線程擁有鎖 ; 在非鎖定狀態下, 沒有線程擁有它。 若要鎖定鎖,線程調用其 [`acquire()`](#threading.RLock.acquire "threading.RLock.acquire") 方法;一旦線程擁有了鎖,方法將返回。若要解鎖,線程調用 [`release()`](#threading.Lock.release "threading.Lock.release") 方法。 [`acquire()`](#threading.Lock.acquire "threading.Lock.acquire")/[`release()`](#threading.Lock.release "threading.Lock.release") 對可以嵌套;只有最終 [`release()`](#threading.Lock.release "threading.Lock.release") (最外面一對的 [`release()`](#threading.Lock.release "threading.Lock.release") ) 將鎖解開,才能讓其他線程繼續處理 [`acquire()`](#threading.Lock.acquire "threading.Lock.acquire") 阻塞。 遞歸鎖也支持 [上下文管理協議](#with-locks)。 *class* `threading.``RLock`此類實現了重入鎖對象。重入鎖必須由獲取它的線程釋放。一旦線程獲得了重入鎖,同一個線程再次獲取它將不阻塞;線程必須在每次獲取它時釋放一次。 需要注意的是 `RLock` 其實是一個工廠函數,返回平臺支持的具體遞歸鎖類中最有效的版本的實例。 `acquire`(*blocking=True*, *timeout=-1*)可以阻塞或非阻塞地獲得鎖。 當無參數調用時: 如果這個線程已經擁有鎖,遞歸級別增加一,并立即返回。否則,如果其他線程擁有該鎖,則阻塞至該鎖解鎖。一旦鎖被解鎖(不屬于任何線程),則搶奪所有權,設置遞歸等級為一,并返回。如果多個線程被阻塞,等待鎖被解鎖,一次只有一個線程能搶到鎖的所有權。在這種情況下,沒有返回值。 當調用時參數 *blocking* 設置為 `True` ,和沒帶參數調用一樣做同樣的事,然后返回 `True` 。 當 *blocking* 參數設置為 false 的情況下調用,不進行阻塞。如果一個無參數的調用已經阻塞,立即返回false;否則,執行和無參數調用一樣的操作,并返回true。 當浮點數 *timeout* 參數被設置為正值調用時,只要無法獲得鎖,將最多阻塞 *timeout* 設定的秒數。 如果鎖被獲取返回 true,如果超時返回false。 在 3.2 版更改: 新的 *timeout* 形參。 `release`()釋放鎖,自減遞歸等級。如果減到零,則將鎖重置為非鎖定狀態(不被任何線程擁有),并且,如果其他線程正被阻塞著等待鎖被解鎖,則僅允許其中一個線程繼續。如果自減后,遞歸等級仍然不是零,則鎖保持鎖定,仍由調用線程擁有。 只有當前線程擁有鎖才能調用這個方法。如果鎖被釋放后調用這個方法,會引起 [`RuntimeError`](exceptions.xhtml#RuntimeError "RuntimeError") 異常。 沒有返回值。 ## 條件對象 條件變量總是與某種類型的鎖對象相關聯,鎖對象可以通過傳入獲得,或者在缺省的情況下自動創建。當多個條件變量需要共享同一個鎖時,傳入一個鎖很有用。鎖是條件對象的一部分,你不必單獨地跟蹤它。 條件變量服從 [上下文管理協議](#with-locks):使用 `with` 語句會在它包圍的代碼塊內獲取關聯的鎖。 [`acquire()`](#threading.Condition.acquire "threading.Condition.acquire") 和 [`release()`](#threading.Condition.release "threading.Condition.release") 方法也能調用關聯鎖的相關方法。 其它方法必須在持有關聯的鎖的情況下調用。 [`wait()`](#threading.Condition.wait "threading.Condition.wait") 方法釋放鎖,然后阻塞直到其它線程調用 [`notify()`](#threading.Condition.notify "threading.Condition.notify") 方法或 [`notify_all()`](#threading.Condition.notify_all "threading.Condition.notify_all") 方法喚醒它。一旦被喚醒, [`wait()`](#threading.Condition.wait "threading.Condition.wait") 方法重新獲取鎖并返回。它也可以指定超時時間。 The [`notify()`](#threading.Condition.notify "threading.Condition.notify") method wakes up one of the threads waiting for the condition variable, if any are waiting. The [`notify_all()`](#threading.Condition.notify_all "threading.Condition.notify_all")method wakes up all threads waiting for the condition variable. 注意: [`notify()`](#threading.Condition.notify "threading.Condition.notify") 方法和 [`notify_all()`](#threading.Condition.notify_all "threading.Condition.notify_all") 方法并不會釋放鎖,這意味著被喚醒的線程不會立即從它們的 [`wait()`](#threading.Condition.wait "threading.Condition.wait") 方法調用中返回,而是會在調用了 [`notify()`](#threading.Condition.notify "threading.Condition.notify") 方法或 [`notify_all()`](#threading.Condition.notify_all "threading.Condition.notify_all") 方法的線程最終放棄了鎖的所有權后返回。 使用條件變量的典型編程風格是將鎖用于同步某些共享狀態的權限,那些對狀態的某些特定改變感興趣的線程,它們重復調用 [`wait()`](#threading.Condition.wait "threading.Condition.wait") 方法,直到看到所期望的改變發生;而對于修改狀態的線程,它們將當前狀態改變為可能是等待者所期待的新狀態后,調用 [`notify()`](#threading.Condition.notify "threading.Condition.notify") 方法或者 [`notify_all()`](#threading.Condition.notify_all "threading.Condition.notify_all") 方法。例如,下面的代碼是一個通用的無限緩沖區容量的生產者-消費者情形: ``` # Consume one item with cv: while not an_item_is_available(): cv.wait() get_an_available_item() # Produce one item with cv: make_an_item_available() cv.notify() ``` 使用 `while` 循環檢查所要求的條件成立與否是有必要的,因為 [`wait()`](#threading.Condition.wait "threading.Condition.wait") 方法可能要經過不確定長度的時間后才會返回,而此時導致 [`notify()`](#threading.Condition.notify "threading.Condition.notify") 方法調用的那個條件可能已經不再成立。這是多線程編程所固有的問題。 [`wait_for()`](#threading.Condition.wait_for "threading.Condition.wait_for") 方法可自動化條件檢查,并簡化超時計算。 ``` # Consume an item with cv: cv.wait_for(an_item_is_available) get_an_available_item() ``` 選擇 [`notify()`](#threading.Condition.notify "threading.Condition.notify") 還是 [`notify_all()`](#threading.Condition.notify_all "threading.Condition.notify_all") ,取決于一次狀態改變是只能被一個還是能被多個等待線程所用。例如在一個典型的生產者-消費者情形中,添加一個項目到緩沖區只需喚醒一個消費者線程。 *class* `threading.``Condition`(*lock=None*)實現條件變量對象的類。一個條件變量對象允許一個或多個線程在被其它線程所通知之前進行等待。 如果給出了非 `None` 的 *lock* 參數,則它必須為 [`Lock`](#threading.Lock "threading.Lock") 或者 [`RLock`](#threading.RLock "threading.RLock") 對象,并且它將被用作底層鎖。否則,將會創建新的 [`RLock`](#threading.RLock "threading.RLock") 對象,并將其用作底層鎖。 在 3.3 版更改: 從工廠函數變為類。 `acquire`(*\*args*)請求底層鎖。此方法調用底層鎖的相應方法,返回值是底層鎖相應方法的返回值。 `release`()釋放底層鎖。此方法調用底層鎖的相應方法。沒有返回值。 `wait`(*timeout=None*)等待直到被通知或發生超時。如果線程在調用此方法時沒有獲得鎖,將會引發 [`RuntimeError`](exceptions.xhtml#RuntimeError "RuntimeError") 異常。 這個方法釋放底層鎖,然后阻塞,直到在另外一個線程中調用同一個條件變量的 [`notify()`](#threading.Condition.notify "threading.Condition.notify") 或 [`notify_all()`](#threading.Condition.notify_all "threading.Condition.notify_all") 喚醒它,或者直到可選的超時發生。一旦被喚醒或者超時,它重新獲得鎖并返回。 當提供了 *timeout* 參數且不是 `None` 時,它應該是一個浮點數,代表操作的超時時間,以秒為單位(可以為小數)。 當底層鎖是個 [`RLock`](#threading.RLock "threading.RLock") ,不會使用它的 [`release()`](#threading.Condition.release "threading.Condition.release") 方法釋放鎖,因為當它被遞歸多次獲取時,實際上可能無法解鎖。相反,使用了 [`RLock`](#threading.RLock "threading.RLock") 類的內部接口,即使多次遞歸獲取它也能解鎖它。 然后,在重新獲取鎖時,使用另一個內部接口來恢復遞歸級別。 返回 `True` ,除非提供的 *timeout* 過期,這種情況下返回 `False`。 在 3.2 版更改: 很明顯,方法總是返回 `None`。 `wait_for`(*predicate*, *timeout=None*)等待,直到條件計算為真。 *predicate* 應該是一個可調用對象而且它的返回值可被解釋為一個布爾值。可以提供 *timeout* 參數給出最大等待時間。 這個實用方法會重復地調用 [`wait()`](#threading.Condition.wait "threading.Condition.wait") 直到滿足判斷式或者發生超時。返回值是判斷式最后一個返回值,而且如果方法發生超時會返回 `False` 。 忽略超時功能,調用此方法大致相當于編寫: ``` while not predicate(): cv.wait() ``` 因此,規則同樣適用于 [`wait()`](#threading.Condition.wait "threading.Condition.wait") :鎖必須在被調用時保持獲取,并在返回時重新獲取。 隨著鎖定執行判斷式。 3\.2 新版功能. `notify`(*n=1*)默認喚醒一個等待這個條件的線程。如果調用線程在沒有獲得鎖的情況下調用這個方法,會引發 [`RuntimeError`](exceptions.xhtml#RuntimeError "RuntimeError") 異常。 這個方法喚醒最多 *n* 個正在等待這個條件變量的線程;如果沒有線程在等待,這是一個空操作。 當前實現中,如果至少有 *n* 個線程正在等待,準確喚醒 *n* 個線程。但是依賴這個行為并不安全。未來,優化的實現有時會喚醒超過 *n* 個線程。 注意:被喚醒的線程實際上不會返回它調用的 [`wait()`](#threading.Condition.wait "threading.Condition.wait") ,直到它可以重新獲得鎖。因為 [`notify()`](#threading.Condition.notify "threading.Condition.notify") 不會釋放鎖,只有它的調用者應該這樣做。 `notify_all`()喚醒所有正在等待這個條件的線程。這個方法行為與 [`notify()`](#threading.Condition.notify "threading.Condition.notify") 相似,但并不只喚醒單一線程,而是喚醒所有等待線程。如果調用線程在調用這個方法時沒有獲得鎖,會引發 [`RuntimeError`](exceptions.xhtml#RuntimeError "RuntimeError") 異常。 ## 信號量對象 這是計算機科學史上最古老的同步原語之一,早期的荷蘭科學家 Edsger W. Dijkstra 發明了它。(他使用名稱 `P()` 和 `V()` 而不是 [`acquire()`](#threading.Semaphore.acquire "threading.Semaphore.acquire") 和 [`release()`](#threading.Semaphore.release "threading.Semaphore.release") )。 一個信號量管理一個內部計數器,該計數器因 [`acquire()`](#threading.Semaphore.acquire "threading.Semaphore.acquire") 方法的調用而遞減,因 [`release()`](#threading.Semaphore.release "threading.Semaphore.release") 方法的調用而遞增。 計數器的值永遠不會小于零;當 [`acquire()`](#threading.Semaphore.acquire "threading.Semaphore.acquire") 方法發現計數器為零時,將會阻塞,直到其它線程調用 [`release()`](#threading.Semaphore.release "threading.Semaphore.release") 方法。 信號量對象也支持 [上下文管理協議](#with-locks) 。 *class* `threading.``Semaphore`(*value=1*)該類實現信號量對象。信號量對象管理一個原子性的計數器,代表 [`release()`](#threading.Semaphore.release "threading.Semaphore.release") 方法的調用次數減去 [`acquire()`](#threading.Semaphore.acquire "threading.Semaphore.acquire") 的調用次數再加上一個初始值。如果需要, [`acquire()`](#threading.Semaphore.acquire "threading.Semaphore.acquire") 方法將會阻塞直到可以返回而不會使得計數器變成負數。在沒有顯式給出 *value* 的值時,默認為1。 可選參數 *value* 賦予內部計數器初始值,默認值為 `1` 。如果 *value* 被賦予小于0的值,將會引發 [`ValueError`](exceptions.xhtml#ValueError "ValueError") 異常。 在 3.3 版更改: 從工廠函數變為類。 `acquire`(*blocking=True*, *timeout=None*)獲取一個信號量。 在不帶參數的情況下調用時: - 如果在進入時,內部計數器的值大于0,將其減1并立即返回true。 - 如果在進入時,內部計數器的值為0,將會阻塞直到被 [`release()`](#threading.Semaphore.release "threading.Semaphore.release") 方法的調用喚醒。一旦被喚醒(并且計數器值大于0),將計數器值減少1并返回true。線程會被每次 [`release()`](#threading.Semaphore.release "threading.Semaphore.release") 方法的調用喚醒。線程被喚醒的次序是不確定的。 在參數 *blocking* 被設置為false的情況下調用,將不會發生阻塞。如果不帶參數的調用會發生阻塞的話,帶參數的調用在相同情況下將會立即返回false。否則,執行和不帶參數的調用一樣的操作并返回true。 當參數 *timeout* 不為 `None` 時,將最多阻塞 *timeout* 秒。如果未能在時間間隔內成功獲取信號量,將返回false,否則返回true。 在 3.2 版更改: 新的 *timeout* 形參。 `release`()釋放一個信號量,將內部計數器的值增加1。當計數器原先的值為0且有其它線程正在等待它再次大于0時,喚醒正在等待的線程。 *class* `threading.``BoundedSemaphore`(*value=1*)該類實現有界信號量。有界信號量通過檢查以確保它當前的值不會超過初始值。如果超過了初始值,將會引發 [`ValueError`](exceptions.xhtml#ValueError "ValueError") 異常。在大多情況下,信號量用于保護數量有限的資源。如果信號量被釋放的次數過多,則表明出現了錯誤。沒有指定時, *value* 的值默認為1。 在 3.3 版更改: 從工廠函數變為類。 ### [`Semaphore`](#threading.Semaphore "threading.Semaphore") 例子 信號量通常用于保護數量有限的資源,例如數據庫服務器。在資源數量固定的任何情況下,都應該使用有界信號量。在生成任何工作線程前,應該在主線程中初始化信號量。 ``` maxconnections = 5 # ... pool_sema = BoundedSemaphore(value=maxconnections) ``` 工作線程生成后,當需要連接服務器時,這些線程將調用信號量的 acquire 和 release 方法: ``` with pool_sema: conn = connectdb() try: # ... use connection ... finally: conn.close() ``` 使用有界信號量能減少這種編程錯誤:信號量的釋放次數多于其請求次數。 ## 事件對象 這是線程之間通信的最簡單機制之一:一個線程發出事件信號,而其他線程等待該信號。 一個事件對象管理一個內部標志,調用 [`set()`](#threading.Event.set "threading.Event.set") 方法可將其設置為true,調用 [`clear()`](#threading.Event.clear "threading.Event.clear") 方法可將其設置為false,調用 [`wait()`](#threading.Event.wait "threading.Event.wait") 方法將進入阻塞直到標志為true。 *class* `threading.``Event`實現事件對象的類。事件對象管理一個內部標志,調用 [`set()`](#threading.Event.set "threading.Event.set") 方法可將其設置為true。調用 [`clear()`](#threading.Event.clear "threading.Event.clear") 方法可將其設置為false。調用 [`wait()`](#threading.Event.wait "threading.Event.wait") 方法將進入阻塞直到標志為true。這個標志初始時為false。 在 3.3 版更改: 從工廠函數變為類。 `is_set`()當且僅當內部標志為true時返回true。 `set`()將內部標志設置為true。所有正在等待這個事件的線程將被喚醒。當標志為true時,調用 [`wait()`](#threading.Event.wait "threading.Event.wait") 方法的線程不會被被阻塞。 `clear`()將內部標志設置為false。之后調用 [`wait()`](#threading.Event.wait "threading.Event.wait") 方法的線程將會被阻塞,直到調用 [`set()`](#threading.Event.set "threading.Event.set") 方法將內部標志再次設置為true。 `wait`(*timeout=None*)阻塞線程直到內部變量為true。如果調用時內部標志為true,將立即返回。否則將阻塞線程,直到調用 [`set()`](#threading.Event.set "threading.Event.set") 方法將標志設置為true或者發生可選的超時。 當提供了timeout參數且不是 `None` 時,它應該是一個浮點數,代表操作的超時時間,以秒為單位(可以為小數)。 當內部標志在調用wait進入阻塞后被設置為true,或者調用wait時已經被設置為true時,方法返回true。 也就是說,除非設定了超時且發生了超時的情況下將會返回false,其他情況該方法都將返回 `True` 。 在 3.1 版更改: 很明顯,方法總是返回 `None`。 ## 定時器對象 此類表示一個操作應該在等待一定的時間之后運行 --- 相當于一個定時器。 [`Timer`](#threading.Timer "threading.Timer") 類是 [`Thread`](#threading.Thread "threading.Thread") 類的子類,因此可以像一個自定義線程一樣工作。 與線程一樣,通過調用 `start()` 方法啟動定時器。而 [`cancel()`](#threading.Timer.cancel "threading.Timer.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=None*, *kwargs=None*)創建一個定時器,在經過 *interval* 秒的間隔事件后,將會用參數 *args* 和關鍵字參數 *kwargs* 調用 *function*。如果 *args* 為 `None` (默認值),則會使用一個空列表。如果 *kwargs* 為 `None` (默認值),則會使用一個空字典。 在 3.3 版更改: 從工廠函數變為類。 `cancel`()停止定時器并取消執行計時器將要執行的操作。僅當計時器仍處于等待狀態時有效。 ## 柵欄對象 3\.2 新版功能. 柵欄類提供一個簡單的同步原語,用于應對固定數量的線程需要彼此相互等待的情況。線程調用 [`wait()`](#threading.Barrier.wait "threading.Barrier.wait") 方法后將阻塞,直到所有線程都調用了 [`wait()`](#threading.Barrier.wait "threading.Barrier.wait") 方法。此時所有線程將被同時釋放。 柵欄對象可以被多次使用,但進程的數量不能改變。 這是一個使用簡便的方法實現客戶端進程與服務端進程同步的例子: ``` b = Barrier(2, timeout=5) def server(): start_server() b.wait() while True: connection = accept_connection() process_server_connection(connection) def client(): b.wait() while True: connection = make_connection() process_client_connection(connection) ``` *class* `threading.``Barrier`(*parties*, *action=None*, *timeout=None*)創建一個需要 *parties* 個線程的柵欄對象。如果提供了可調用的 *action* 參數,它會在所有線程被釋放時在其中一個線程中自動調用。 *timeout* 是默認的超時時間,如果沒有在 [`wait()`](#threading.Barrier.wait "threading.Barrier.wait") 方法中指定超時時間的話。 `wait`(*timeout=None*)沖出柵欄。當柵欄中所有線程都已經調用了這個函數,它們將同時被釋放。如果提供了 *timeout* 參數,這里的 *timeout* 參數優先于創建柵欄對象時提供的 *timeout* 參數。 函數返回值是一個整數,取值范圍在0到 *parties* -- 1,在每個線程中的返回值不相同。可用于從所有線程中選擇唯一的一個線程執行一些特別的工作。例如: ``` i = barrier.wait() if i == 0: # Only one thread needs to print this print("passed the barrier") ``` 如果創建柵欄對象時在構造函數中提供了 *action* 參數,它將在其中一個線程釋放前被調用。如果此調用引發了異常,柵欄對象將進入損壞態。 如果發生了超時,柵欄對象將進入破損態。 如果柵欄對象進入破損態,或重置柵欄時仍有線程等待釋放,將會引發 [`BrokenBarrierError`](#threading.BrokenBarrierError "threading.BrokenBarrierError") 異常。 `reset`()重置柵欄為默認的初始態。如果柵欄中仍有線程等待釋放,這些線程將會收到 [`BrokenBarrierError`](#threading.BrokenBarrierError "threading.BrokenBarrierError") 異常。 注意使用此函數時,如果有某些線程狀態未知,則可能需其它的同步來確保線程已被釋放。如果柵欄進入了破損態,最好廢棄它并新建一個柵欄。 `abort`()使柵欄進入破損態。這將導致所有已經調用和未來調用的 [`wait()`](#threading.Barrier.wait "threading.Barrier.wait") 方法中引發 [`BrokenBarrierError`](#threading.BrokenBarrierError "threading.BrokenBarrierError") 異常。使用這個方法的一種情況是需要中止程序以避免死鎖。 更好的方式是:創建柵欄時提供一個合理的超時時間,來自動避免某個線程出錯。 `parties`沖出柵欄所需要的線程數量。 `n_waiting`當前時刻正在柵欄中阻塞的線程數量。 `broken`一個布爾值,值為 `True` 表明柵欄為破損態。 *exception* `threading.``BrokenBarrierError`異常類,是 [`RuntimeError`](exceptions.xhtml#RuntimeError "RuntimeError") 異常的子類,在 [`Barrier`](#threading.Barrier "threading.Barrier") 對象重置時仍有線程阻塞時和對象進入破損態時被引發。 ## 在 `with` 語句中使用鎖、條件和信號量 這個模塊提供的帶有 `acquire()` 和 `release()` 方法的對象,可以被用作 [`with`](../reference/compound_stmts.xhtml#with) 語句的上下文管理器。當進入語句塊時 `acquire()` 方法會被調用,退出語句塊時 `release()` 會被調用。因此,以下片段: ``` with some_lock: # do something... ``` 相當于: ``` some_lock.acquire() try: # do something... finally: some_lock.release() ``` 現在 [`Lock`](#threading.Lock "threading.Lock") 、 [`RLock`](#threading.RLock "threading.RLock") 、 [`Condition`](#threading.Condition "threading.Condition") 、 [`Semaphore`](#threading.Semaphore "threading.Semaphore") 和 [`BoundedSemaphore`](#threading.BoundedSemaphore "threading.BoundedSemaphore") 對象可以用作 [`with`](../reference/compound_stmts.xhtml#with) 語句的上下文管理器。 ### 導航 - [索引](../genindex.xhtml "總目錄") - [模塊](../py-modindex.xhtml "Python 模塊索引") | - [下一頁](multiprocessing.xhtml "multiprocessing --- 基于進程的并行") | - [上一頁](concurrency.xhtml "并發執行") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) ? - zh\_CN 3.7.3 [文檔](../index.xhtml) ? - [Python 標準庫](index.xhtml) ? - [并發執行](concurrency.xhtml) ? - $('.inline-search').show(0); | ? [版權所有](../copyright.xhtml) 2001-2019, Python Software Foundation. Python 軟件基金會是一個非盈利組織。 [請捐助。](https://www.python.org/psf/donations/) 最后更新于 5月 21, 2019. [發現了問題](../bugs.xhtml)? 使用[Sphinx](http://sphinx.pocoo.org/)1.8.4 創建。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看