【同步】:python
兩個或兩個以上的進程或線程在運行過程當中協同步調,按預約的前後次序運行。好比 A 任務的運行依賴於 B 任務產生的數據。安全
【互斥】:併發
一個公共資源同一時刻只能被一個進程或線程使用,多個進程或線程不能同時使用公共資源。app
鎖只是鎖住修改共享數據的部分,即部分串行,要想保證數據安全的根本原理在於讓併發變成串行,join與互斥鎖均可以實現,毫無疑問,互斥鎖的部分串行效率要更高
把原來的併發執行變成串行,犧牲了執行效率保證了數據安全dom
這邊的同步鎖至關於互斥鎖,爲了安全修改數據,把整個修改數據的過程變成串行ui
from threading import Thread,Lock import os,time def work(): global n lock.acquire() temp=n time.sleep(0.1) n=temp-1 lock.release() if __name__ == '__main__': lock=Lock() n=100 l=[] for i in range(100): p=Thread(target=work) l.append(p) p.start() for p in l: p.join() print(n) #結果確定爲0,
#不加鎖:併發執行,速度快,數據不安全 from threading import current_thread,Thread,Lock import os,time def task(): global n print('%s is running' %current_thread().getName()) temp=n time.sleep(0.5) n=temp-1 if __name__ == '__main__': n=100 lock=Lock() threads=[] start_time=time.time() for i in range(100): t=Thread(target=task) threads.append(t) t.start() for t in threads: t.join() stop_time=time.time() print('主:%s n:%s' %(stop_time-start_time,n)) ''' Thread-1 is running Thread-2 is running ...... Thread-100 is running 主:0.5216062068939209 n:99 ''' #不加鎖:未加鎖部分併發執行,加鎖部分串行執行,速度慢,數據安全 from threading import current_thread,Thread,Lock import os,time def task(): #未加鎖的代碼併發運行 time.sleep(3) print('%s start to run' %current_thread().getName()) global n #加鎖的代碼串行運行 lock.acquire() temp=n time.sleep(0.5) n=temp-1 lock.release() if __name__ == '__main__': n=100 lock=Lock() threads=[] start_time=time.time() for i in range(100): t=Thread(target=task) threads.append(t) t.start() for t in threads: t.join() stop_time=time.time() print('主:%s n:%s' %(stop_time-start_time,n)) ''' Thread-1 is running Thread-2 is running ...... Thread-100 is running 主:53.294203758239746 n:0 ''' #有的同窗可能有疑問:既然加鎖會讓運行變成串行,那麼我在start以後當即使用join,就不用加鎖了啊,也是串行的效果啊 #沒錯:在start以後馬上使用jion,確定會將100個任務的執行變成串行,毫無疑問,最終n的結果也確定是0,是安全的,但問題是 #start後當即join:任務內的全部代碼都是串行執行的,而加鎖,只是加鎖的部分即修改共享數據的部分是串行的 #單從保證數據安全方面,兩者均可以實現,但很明顯是加鎖的效率更高. from threading import current_thread,Thread,Lock import os,time def task(): time.sleep(3) print('%s start to run' %current_thread().getName()) global n temp=n time.sleep(0.5) n=temp-1 if __name__ == '__main__': n=100 lock=Lock() start_time=time.time() for i in range(100): t=Thread(target=task) t.start() t.join() stop_time=time.time() print('主:%s n:%s' %(stop_time-start_time,n)) ''' Thread-1 start to run Thread-2 start to run ...... Thread-100 start to run 主:350.6937336921692 n:0 #耗時是多麼的恐怖 ''' )
所謂死鎖: 是指兩個或兩個以上的進程或線程在執行過程當中,因爭奪資源而形成的一種互相等待的現象線程
from threading import Lock as Lock import time mutexA=Lock() mutexA.acquire() mutexA.acquire() print(123) mutexA.release() mutexA.release()
解決方法,遞歸鎖,在Python中爲了支持在同一線程中屢次請求同一資源,python提供了可重入鎖RLock。code
from threading import Thread,Lock,current_thread,RLock import time """ Rlock能夠被第一個搶到鎖的人連續的acquire和release 每acquire一次鎖身上的計數加1 每release一次鎖身上的計數減1 只要鎖的計數不爲0 其餘人都不能搶 """ # mutexA = Lock() # mutexB = Lock() mutexA = mutexB = RLock() # A B如今是同一把鎖 class MyThread(Thread): def run(self): # 建立線程自動觸發run方法 run方法內調用func1 func2至關於也是自動觸發 self.func1() self.func2() def func1(self): mutexA.acquire() print('%s搶到了A鎖'%self.name) # self.name等價於current_thread().name mutexB.acquire() print('%s搶到了B鎖'%self.name) mutexB.release() print('%s釋放了B鎖'%self.name) mutexA.release() print('%s釋放了A鎖'%self.name) def func2(self): mutexB.acquire() print('%s搶到了B鎖'%self.name) time.sleep(1) mutexA.acquire() print('%s搶到了A鎖' % self.name) mutexA.release() print('%s釋放了A鎖' % self.name) mutexB.release() print('%s釋放了B鎖' % self.name) for i in range(10): t = MyThread() t.start() # class Demo(object): # # pass # # # # obj1 = Demo() # # obj2 = Demo() # # print(id(obj1),id(obj2)) """ 只要類加括號實例化對象 不管傳入的參數是否同樣生成的對象確定不同 單例模式除外 本身千萬不要輕易的處理鎖的問題 """
Semaphore管理一個內置的計數器,
每當調用acquire()時內置計數器-1;
調用release() 時內置計數器+1;
計數器不能小於0;當計數器爲0時,acquire()將阻塞線程直到其餘線程調用release()。對象
實例:(同時只有5個線程能夠得到semaphore,便可以限制最大鏈接數爲5):遞歸
與進程池是徹底不一樣的概念,進程池Pool(4),最大隻能產生4個進程,並且從頭至尾都只是這四個進程,不會產生新的,而信號量是產生一堆線程/進程
# 信號量可能在不一樣的領域中 對應不一樣的知識點 """ 互斥鎖:一個廁所(一個坑位) 信號量:公共廁所(多個坑位) """ from threading import Semaphore,Thread import time import random n = 100 sm = Semaphore(5) # 造了一個含有五個的坑位的公共廁所 def task(name): global n sm.acquire() print('%s佔了一個坑位'%name) time.sleep(1) # time.sleep(random.randint(1,3)) n = n - 1 print(n) sm.release() for i in range(40): t = Thread(target=task,args=(i,)) t.start()