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
模組提供。
一個原始鎖有兩個狀態:locked
和unlocked
。鎖建立時,處於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物件
Timer
是Thread
的子類,所以也要接受function
引數,也可以被start()
。 它的run()
函式被重寫為先event.wait(interval)
,再啟動function
。
Barrier物件
實現某些服務的共進退。
threading.Barrier(parties, action=None, timeout=None)
設定n=parties
個執行緒,當n
個barrier.wait()
被呼叫後,所有這些呼叫的阻塞被同時解除,執行action
感覺Barrier
可以實現很多複雜的功能。