鎖對象html
原始鎖是一個在鎖定時不屬於特定線程的同步基元組件。在Python中,它是能用的最低級的同步基元組件,由 _thread
擴展模塊直接實現。面試
原始鎖處於 "鎖定" 或者 "非鎖定" 兩種狀態之一。它被建立時爲非鎖定狀態。它有兩個基本方法, acquire()
和 release()
。當狀態爲非鎖定時, acquire()
將狀態改成 鎖定 並當即返回。當狀態是鎖定時, acquire()
將阻塞至其餘線程調用 release()
將其改成非鎖定狀態,而後 acquire()
調用重置其爲鎖定狀態並返回。 release()
只在鎖定狀態下調用; 它將狀態改成非鎖定並當即返回。若是嘗試釋放一個非鎖定的鎖,則會引起 RuntimeError
異常。數據庫
鎖一樣支持 上下文管理協議。編程
當多個線程在 acquire()
等待狀態轉變爲未鎖定被阻塞,而後 release()
重置狀態爲未鎖定時,只有一個線程能繼續執行;至於哪一個等待線程繼續執行沒有定義,而且會根據實現而不一樣。服務器
acquire
(blocking=True, timeout=-1)能夠阻塞或非阻塞地得到鎖。當調用時參數 blocking 設置爲 True
(缺省值),阻塞直到鎖被釋放,而後將鎖鎖定並返回 True
。在參數 blocking 被設置爲 False
的狀況下調用,將不會發生阻塞。若是調用時 blocking 設爲 True
會阻塞,並當即返回 False
;不然,將鎖鎖定並返回 True
。當浮點型 timeout 參數被設置爲正值調用時,只要沒法得到鎖,將最多阻塞 timeout 設定的秒數。timeout 參數被設置爲 -1
時將無限等待。當 blocking 爲 false 時,timeout 指定的值將被忽略。若是成功得到鎖,則返回 True
,不然返回 False
(例如發生 超時 的時候)。app
release
()dom
RuntimeError
異常。沒有返回值。
重入鎖是一個能夠被同一個線程屢次獲取的同步基元組件。在內部,它在基元鎖的鎖定/非鎖定狀態上附加了 "所屬線程" 和 "遞歸等級" 的概念。在鎖定狀態下,某些線程擁有鎖 ; 在非鎖定狀態下, 沒有線程擁有它。ide
若要鎖定鎖,線程調用其 acquire()
方法;一旦線程擁有了鎖,方法將返回。若要解鎖,線程調用 release()
方法。 acquire()
/release()
對能夠嵌套;只有最終 release()
(最外面一對的 release()
) 將鎖解開,才能讓其餘線程繼續處理 acquire()
阻塞。函數
遞歸鎖也支持 上下文管理協議。ui
條件變量老是與某種類型的鎖對象相關聯,鎖對象能夠經過傳入得到,或者在缺省的狀況下自動建立。當多個條件變量須要共享同一個鎖時,傳入一個鎖頗有用。鎖是條件對象的一部分,你沒必要單獨地跟蹤它。
條件變量服從 上下文管理協議:使用 with
語句會在它包圍的代碼塊內獲取關聯的鎖。 acquire()
和 release()
方法也能調用關聯鎖的相關方法。
其它方法必須在持有關聯的鎖的狀況下調用。 wait()
方法釋放鎖,而後阻塞直到其它線程調用 notify()
方法或 notify_all()
方法喚醒它。一旦被喚醒, wait()
方法從新獲取鎖並返回。它也能夠指定超時時間。
The notify()
method wakes up one of the threads waiting for the condition variable, if any are waiting. The notify_all()
method wakes up all threads waiting for the condition variable.
注意: notify()
方法和 notify_all()
方法並不會釋放鎖,這意味着被喚醒的線程不會當即從它們的 wait()
方法調用中返回,而是會在調用了 notify()
方法或 notify_all()
方法的線程最終放棄了鎖的全部權後返回。
使用條件變量的典型編程風格是將鎖用於同步某些共享狀態的權限,那些對狀態的某些特定改變感興趣的線程,它們重複調用 wait()
方法,直到看到所指望的改變發生;而對於修改狀態的線程,它們將當前狀態改變爲多是等待者所期待的新狀態後,調用 notify()
方法或者 notify_all()
方法。
這是計算機科學史上最古老的同步原語之一,早期的荷蘭科學家 Edsger W. Dijkstra 發明了它。(他使用名稱 P()
和 V()
而不是 acquire()
和 release()
)。
一個信號量管理一個內部計數器,該計數器因 acquire()
方法的調用而遞減,因 release()
方法的調用而遞增。 計數器的值永遠不會小於零;當 acquire()
方法發現計數器爲零時,將會阻塞,直到其它線程調用 release()
方法。
這是線程之間通訊的最簡單機制之一:一個線程發出事件信號,而其餘線程等待該信號。
一個事件對象管理一個內部標誌,調用 set()
方法可將其設置爲true,調用 clear()
方法可將其設置爲false,調用 wait()
方法將進入阻塞直到標誌爲true。
此類表示一個操做應該在等待必定的時間以後運行 --- 至關於一個定時器。 Timer
類是 Thread
類的子類,所以能夠像一個自定義線程同樣工做。
與線程同樣,經過調用 start()
方法啓動定時器。而 cancel()
方法能夠中止計時器(在計時結束前), 定時器在執行其操做以前等待的時間間隔可能與用戶指定的時間間隔不徹底相同。
3.2 新版功能.
柵欄類提供一個簡單的同步原語,用於應對固定數量的線程須要彼此相互等待的狀況。線程調用 wait()
方法後將阻塞,直到全部線程都調用了 wait()
方法。此時全部線程將被同時釋放。
柵欄對象能夠被屢次使用,但進程的數量不能改變。
from threading import Thread,Lock import random # 鎖的做用 # arr = [] # # #原始鎖處於 "鎖定" 或者 "非鎖定" 兩種狀態之一。它被建立時爲非鎖定狀態。它有兩個基本方法, acquire() 和 release() 。當狀態爲非鎖定時, acquire() 將狀態改成 鎖定 並當即返回。當狀態是鎖定時, acquire() 將阻塞至其餘線程調用 release() 將其改成非鎖定狀態,而後 acquire() 調用重置其爲鎖定狀態並返回。 release() 只在鎖定狀態下調用; 它將狀態改成非鎖定並當即返回。若是嘗試釋放一個非鎖定的鎖,則會引起 RuntimeError 異常。 # # l = Lock() # 狀態默認是非鎖定的 # l.acquire() # # def test1(): # l.acquire() # 若是以前的鎖是鎖定的,再次上鎖發生阻塞 # # 若是以前的鎖是非鎖定的,能夠實現上鎖 # arr.append(random.randint(1,10)) # # t = Thread(target=test1) # t.start() # # # # def test2(): # arr.append(random.randint(1,0)) """ 爬取豆瓣電影top250 """ # import requests # import lxml.etree as etree # urls = ["https://movie.douban.com/top250?start=%s"%i for i in range(0,226,25)] # # class Mytest(Thread): # def __init__(self): # super(Mytest,self).__init__() # def run(self): # while len(urls)>0: # url = urls.pop() # res = requests.get(url).text # html = etree.HTML(res) # titles = html.xpath("//div[@class='hd']/a/span[1]/text()") # print(self.name,titles) # # for i in range(2): # mytest = Mytest() # mytest.start() """ 向列表中插入元素並打印列表 """ # import time # arr = [] # l = Lock() # class Mytest(Thread): # def __init__(self): # super(Mytest,self).__init__() # def run(self): # time.sleep(1) # l.acquire() # arr.append(random.randint(0,10)) # print(arr) # l.release() # # for i in range(20): # t = Mytest() # t.start() """ 遞歸鎖 複用鎖 RLock() 在一個線程內能夠重複上鎖不被阻塞。 """ from threading import RLock import time r = RLock() l = Lock() def test1(): r.acquire() r.acquire() print("123") time.sleep(2) r.release() r.release() def test2(): r.acquire() print('test2') t = Thread(target=test1) t.start() t2 = Thread(target=test2) t2.start() # 死鎖 # import time # l1 = Lock() # l2 = Lock() # def fun1(): # l1.acquire() # print("fun1 is running") # time.sleep(1) # l2.acquire() # 阻塞 # print("fun1 is end") # l1.release() # l2.acquire() # def fun2(): # l2.acquire() # print("fun2 is running") # l1.acquire() # 阻塞 # print("fun2 is end") # l2.release() # l1.release() # # t1 = Thread(target=fun1) # t1.start() # t2 = Thread(target=fun2) # t2.start() """ 鎖的上下文使用方法 向列表中插入元素並打印列表 """ # import time,random # arr = [] # l = Lock() # def fun(): # time.sleep(1) # with l: # 上鎖 自動解鎖的功能 # arr.append(random.randint(0,10)) # print(arr) # # for i in range(20): # t = Thread(target=fun) # t.start() """ 條件鎖 class Condition(lock=RLock) 默認是遞歸鎖 方法: acquire() 上鎖 release() 釋放鎖 wait(timeout=) 等待(釋放鎖) 阻塞(等待被通知) notify(n=) 通知 喚醒n個線程 wait_for(predicate,timeout=) predicate 是一個函數 返回 True False notify_all() 喚醒全部線程 """ # from threading import Condition # import time # con = Condition(lock=Lock()) # # arr = [] # # class XM(Thread): # def __init__(self): # super(XM,self).__init__() # def run(self): # with con: # while True: # time.sleep(1) # arr.append(1) # length = len(arr) # print("小明添加了1個魚丸,鍋內還有%s個魚丸"%length) # if length>=5: # con.notify_all() # con.wait() # # # class XH(Thread): # def __init__(self,name): # super(XH,self).__init__() # self.name = name # def run(self): # with con: # while True: # time.sleep(1) # arr.pop() # length = len(arr) # print("%s吃了1個魚丸,鍋內還有%s個魚丸"%(self.name,length)) # if length<=0: # con.notify() # con.wait() # # xm = XM() # xm.start() # # xh = XH("小紅1") # xh.start() # # xh1 = XH("小紅2") # xh1.start() """ wait_for(predicate,timeout=) 等待 當predicate 返回值爲 False 阻塞 當返回值爲True 運行 wait() 等待,阻塞 。直到被 notify """ # from threading import Condition # import time # con = Condition() # con.acquire() # # def fun(): # time.sleep(5) # return True # con.wait_for(fun) # print(123) """ Semaphore 信號量對象 信號量一般用於保護數量有限的資源,例如數據庫服務器。在資源數量固定的任何狀況下,都應該使用有界信號量。在生成任何工做線程前,應該在主線程中初始化信號量。 """ # from threading import Semaphore # import time # b = Semaphore(value=3) # 技術面試 每次3我的 # class Ms(Thread): # def __init__(self): # super(Ms,self).__init__() # def run(self): # with b: # print("<%s>開始面試,倒計時3秒鐘"%self.name) # time.sleep(3) # print("<%s>面試結束,有請下一個同窗"%self.name) # # # for i in range(20): # m = Ms() # m.start() """ 事件鎖 is_set() 判斷事件鎖內部開關是否爲true set() 設置事件鎖內部開關爲 true clear() 設置事件鎖內部開關爲 false wait() 阻塞 等待事件鎖內部開關爲true 而後運行 """ # from threading import Event # import time # # e1 = Event() # e1.set() # # e2 = Event() # # arr = [] # class XM(Thread): # def __init__(self): # super(XM,self).__init__() # def run(self): # while True: # e1.wait() # time.sleep(1) # arr.append(1) # length = len(arr) # print("小明添加了1個魚丸,鍋內還有%s個魚丸"%length) # if length>=5: # e1.clear() # e2.set() # # class XH(Thread): # def __init__(self): # super(XH, self).__init__() # def run(self): # while True: # e2.wait() # time.sleep(1) # arr.pop() # length = len(arr) # print("小紅吃了1個魚丸,鍋內還剩%s個魚丸"%length) # if length<=0: # e2.clear() # e1.set() # # xm = XM() # xm.start() # xh = XH() # xh.start() """ 定時器對象 """ # import time # def fun(): # time.sleep(3) # print("123") # # fun() # print("開始") # from threading import Timer # # Timer 是一個倒計時線程 # def fun(): # print("123") # # t = Timer(3,fun) # t.start() # print("開始") """ 柵欄對象 wait() """ # from threading import Barrier,active_count # import time # # b = Barrier(5) # l = Lock() # # class Test(Thread): # def __init__(self): # super(Test,self).__init__() # def run(self): # b.wait() # with l: # print("%s 開始運行"%self.name) # # for i in range(20): # time.sleep(2) # t = Test() # with l: # print("建立了%s線程"%t.name) # t.start()