通讀Python官方文件之Threading

PETCoder亞洲善待程式猿組織發表於2019-02-16

Python的threading模組鬆散地基於Java的threading模組。但現線上程沒有優先順序,沒有執行緒組,不能被銷燬、停止、暫停、開始和打斷。 Java Thread類的靜態方法,被移植成了模組方法。

main thread: 執行python程式的執行緒

daemon thread 守護執行緒,如果守護執行緒之外的執行緒都結束了。守護執行緒也會結束,並強行終止整個程式。不要在守護程式中進行資源相關操作。會導致資源不能正確的釋放。在非守護程式中使用Event

Thread 類

(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None)

group: 為以後的ThreadGroup類預留
target: 被執行的物件,由run()方法執行
args: target物件使用的引數
daemon: 是否為守護程式

start()


每個thread 物件都只能被呼叫1次start()

run()


如果建立Thread的子類,重寫該方法。負責執行target引數傳來的可執行物件。

join()


阻塞執行緒直到結束。

GIL

CPython中,由於GIL的存在,Python每次只能執行一個執行緒。如果要充分利用多核機器的計算資源需要使用multiprocessing或者是concurrent.futures.ProcessPollExecutor但,但如果你想要很多I/O相關的併發操作,threding仍然是一個很好的選擇 。?因為系統自動實現了執行緒的上下文切換。

from threading import Thread
import requests

url = `http://www.baidu.com`

urls = [url]*20
threads = []

for url in urls:
    t = Thread(target=requests.get, args=(url, ))
    t.start()
    threads.append(t)

for t in threads:
    t.join()

鎖(Lock)物件

原始鎖(primitive lock),當它鎖住的時候,它是一種不屬於任何一個執行緒的同步原語(synchronization primitive)。 在Python中,他是目前可用的最底層的同步原語,由_thread模組提供。

一個原始鎖有兩個狀態:lockedunlocked。鎖建立時,處於unlocked狀態。 鎖由兩個基本方法:acquire()release()

當處於unlocked狀態時,acquire(()方法可以將狀態變為locked,並立即返回。當處於locked狀態時,acquire()會阻塞直至另一個執行緒呼叫了release()使改鎖解鎖,然後acquire()將鎖上鎖,並返回。

release()方法只能在鎖locked時別呼叫,並釋放鎖。否則會丟擲RuntimeError錯誤。

如果有多個 acquire()在等待解鎖,則不確定哪一個哪一個會被觸發。

class threading.Lock

如果一個執行緒acquire了一個鎖,那麼後續獲取它的執行緒都會被阻塞,直至鎖被釋放。任何執行緒都可以釋放鎖。

Lock是一個工廠函式,返回當前平臺下最高效的concrete Lock類的例項。

Lock支援上下文管理方法(context management protocol),也就是with 語句。在存在競態條件(race condition)的時候,要使用鎖。比如多執行緒共同操作某個資料。

# 摘自python Cookbook
import threading

class SharedCounter:

    def __init__(self, init_value=0):
        self._value  = init_value
        self._value_lock = threading.Lock()
    
    def incr(self, delta=1):
        # 在這裡使用了with 語句,建立一個鎖,增加值,釋放鎖。
        with self._value_lock:
            self._value += 1

RLock物件

可重入鎖(reentrant lock)。感覺是一個鎖中鎖,就是可以遞迴的鎖。等見到具體的應用例子再寫。

Condition物件

condition變數總是與某種鎖相關,鎖可以是傳過來的,也可以通過預設設定建立。如果有多個 condition物件需要共享一個鎖時,傳遞一個鎖是非常有用的。鎖是condition物件的一部分,你不用刻意的跟蹤它。

Timer物件

TimerThread的子類,所以也要接受function引數,也可以被start()。 它的run()函式被重寫為先event.wait(interval),再啟動function

Barrier物件

實現某些服務的共進退。

threading.Barrier(parties, action=None, timeout=None)

設定n=parties個執行緒,當nbarrier.wait()被呼叫後,所有這些呼叫的阻塞被同時解除,執行action

感覺Barrier可以實現很多複雜的功能。


參考資料:

Python threading

相關文章