執行緒同步
概念執行緒同步,執行緒間協同,通過某種技術,讓乙個執行緒訪問某些資料時,其他執行緒不能訪問這些資料,直到該執行緒完成對資料的操作.
臨界區(critical section) 互斥量(mutex) 訊號量(semaphore) 時間(event)
event事件
event事件,是執行緒間通訊機制中最簡單的實現,使用乙個內部標記的flag,通過flag的true或false的變化來進行操作.
名稱含義
set()
標記設定為true
clear()
標記設定為false
is_set()
標記是否為true
wait(timeout=none)
設定等標記為true的時長,none為無限等待.等到返回true,未等到超時返回false,不設定預設無限等
總結使用同乙個event物件的標記flag
誰wait就是等到flag變為true,或等到超時返回false,不限制等待個數
wait的使用
event的wait優於time.sleep,它會更快的切換到其他程序,提高併發效率.
lock(互斥鎖,互斥量)
鎖,凡是存在共享資源爭搶的地方都可以使用鎖,從而保證只有乙個使用者可以完全使用這個資源.
一旦執行緒獲得鎖,其他試圖獲取鎖的執行緒將被阻塞
名稱含義
acquire(blocking=true,timeout=-1)
預設阻塞,阻塞可以設定超時時間.非阻塞時,timeout禁止設定.成功獲取鎖,返回true,否則返回false
release()
釋放鎖,可以從任何執行緒呼叫釋放.已上鎖的鎖,會被重置為unlocked未上鎖的鎖上呼叫,拋runtimeerror異常
加鎖,解鎖
一般來說,有加鎖就需要解鎖,一旦加鎖後解鎖前,還要執行一些**,就可能拋異常,鎖無法釋放,但是當前執行緒就可能因為這個異常被終止,產生死鎖.一般為邏輯問題.
常用語句:
使用try,,,finally語句保證鎖的釋放
with上下文管理,鎖物件支援上下文管理
注意事項:
少用.使用了鎖,多執行緒訪問被鎖的資源時,就成了序列,要麼排隊執行,要麼爭搶執行
加鎖時間越短越好,不需要就立即釋放鎖
一定要避免死鎖
遞迴鎖rlock(可重入鎖)
遞迴鎖,是執行緒相關鎖,個人認為,鎖的是乙個執行緒
當鎖未釋放完,其他執行緒獲取鎖會被阻塞,知道當前持有鎖的執行緒釋放完鎖
condition
構造方法:condition(lock= none),可以摻入乙個lock或者rlock鎖物件,預設rlock
名稱含義
acquire(*args)
獲取鎖wait()
等待或超時
notify(n= 1)
喚醒之多指定數目個數的等待執行緒,沒有等待的執行緒就沒有任何操作
notify_all()
喚醒所有等待的執行緒
總結condition用於生成者消費者模型中,解決生產者消費者速度匹配的問題.
採用通知機制,效率極高
使用方法:
使用condition,必須先acquire,用完了要release,預設使用rlock.最好的方式是使用with上下文
消費者wait,等待通知
生產者生產好訊息,對消費者傳送通知,可以使用notify或者notify_all方法.
barrier柵欄(路閘)
wait超時
semaphore訊號量
和lock很想,訊號量物件內部維護乙個倒計數器,每一次acquire都會減1,當acquire方法發現技術為0就阻塞請求的執行緒,知道其他執行緒對訊號量release後,計數大於0,恢復阻塞的執行緒.
名稱含義
semaphore(value=1)
構造方法.value小於0,拋valueerror異常
acquire()
獲取訊號量,計數器減1,成功返回true
release()
釋放訊號量,計數器加1
計數器永遠不會低於0,因為acquire的時候,發現是0,都會被阻塞.
from threading import semaphore,lock
from threading import current_thread
from threading import thread
import time
sm = semaphore(5)#5個馬桶
def task():
sm.acquire()
print(f' work')
time.sleep(1)
sm.release()
for line in range(20):
t.thread(target=task)
t.start
訊號量和鎖
鎖,值允許同乙個時間乙個執行緒獨佔資源,它是特殊的訊號量,即訊號量計數器初值為1.
訊號量,可以多個執行緒訪問共享資源,但這個共享資源數量有限.
資料結構和gil
queue
標準庫queue模組,提供
fifo的佇列:先進先出
lifo的佇列:後進先出
優先佇列:根據引數內,數字的大小進行分級,數值越小,優先順序越高(字串會有自己的演算法,不建議使用)
queue是執行緒安全的,適用於多執行緒間安全的交換資料.內部使用了lock,condition
import queue
q = queue.queue()
q.put(1)
q.put(2)
q.put(3)
print(q.get()) #1
q = queue.lifoqueue()
q.put(1)
q.put(2)
q.put(3)
print(q.get()) # 3
gil全域性直譯器鎖(global interpreter lock)
cpython在直譯器程序級別有把鎖.叫gil全域性直譯器鎖.
gil保證cpython程序中,只有乙個執行緒執行位元組碼,甚至多核cpu情況下,也會當乙個程序a中的執行緒執行時,阻塞其他cpu上a程序的執行緒.相當於,cpython中永遠沒有真正微觀實際意義上的多執行緒.
cpython中,io密集型,使用多執行緒;cpu密集型,使用多繼承,繞開gil
ruby也有gil,如果高併發的話,用erlang或者go
python中絕大多數內建資料結構讀寫都是原子操作.(即不會被優先順序更高的執行緒打斷,執行緒安全)
由於gil存在,python的內建資料型別在多執行緒程式設計的時候就變程了安全的了,但是實際上他們本身不是執行緒安全型別.
原子操作:原子操作,就是不能被更高等級中斷搶奪優先的操作。由於作業系統大部分時間處於開中斷狀態,所以,乙個程式在執行的時候可能被優先順序更高的執行緒中斷。而有些操作是不能被中斷的,不然會出現無法還原的後果,這時候,這些操作就需要原子操作。就是不能被中斷的操作。
執行緒喚醒機制
object類中提供了三個方法 wait 等待 notify 喚醒單個執行緒 notifyall 喚醒所有執行緒 public class student public class setthread implements runnable override public void run catc...
C 自動喚醒執行緒
在通常的程式設計中,我們時常會不斷地啟動新執行緒來完成不斷出現的新任務.而由於任務的大小不確定性,以及出現要處理的任務的時間的不確定性,使得我們的好多程式總是在不斷地在開啟執行緒,並完成某任務後就退出執行緒.當每次任務不大,可又總是有任務頻繁出現時,總是不斷地開啟並退出執行緒.這開啟並退出執行緒所消...
執行緒等待與喚醒
標籤 多執行緒 所有的等待和喚醒執行緒,都是針對某個具體物件例項的.api介面 說明wait 讓當前執行緒進入等待 阻塞 狀態,直到其他執行緒呼叫此物件的notify 或notifyall 來喚醒,之後該執行緒進入就緒狀態.wait long timeout 讓當前執行緒進入阻塞狀態,直到其他執行緒...