1、死鎖
定義; 類似兩個人分別被囚禁在兩間房子裡,A手上拿著的是B囚禁房間的鑰匙,而B拿著A的鑰匙,兩個人都沒法出去,沒法給對方開鎖,進而造成死鎖現象。
具體例子程式碼如下:
# -*-coding:utf-8 -*- from threading import Thread,Lock,RLock import time muxeA=Lock() muxeB=Lock() class MyThread(Thread): def run(self): self.func1() self.func2() def func1(self): muxeA.acquire() print('%s搶到A鎖了'%self.name) muxeB.acquire() print('%s搶到B鎖了' % self.name) muxeB.release() muxeA.release() def func2(self): muxeB.acquire() print('%s搶到B鎖了' % self.name) time.sleep(2) muxeA.acquire() print('%s搶到A鎖了' % self.name) muxeA.release() muxeB.release() if __name__ == '__main__': for i in range(10): t=MyThread() t.start()
分析:
當執行func1的時候,第一個人(a)先搶到鎖A,這時候,
其他人只能繼續等待搶鎖A,沒有人跟a搶鎖B,所以a也搶到鎖B,
拿到鎖B後,a就把鎖B先釋放掉,再釋放鎖A,
繼續執行func2,a也順利搶到鎖B,這時候,睡眠2s,
而鎖A已經被第二個人搶到了,這時候,第二個人只拿到鎖A,沒有拿到鎖B,
所以沒有釋放鎖A,而a一直在等待搶鎖A,沒有釋放鎖B,
所以這時候就造成等待死迴圈的情況。
執行結果如下:
遞迴鎖使用:from reading import RLock
遞迴鎖的特點:
1、可以被連續的acquire和release
2、但是,只能第一個搶到這把鎖執行上述操作
3、它內部有一個計數器,每acquire一次計數加一,每realse一次計數減一
4、只要計數不為0,那麼其他人都無法搶到該鎖
具體例子程式碼如下:
# -*-coding:utf-8 -*- from threading import Thread,RLock import time muxeA=muxeB=RLock() class MyThread(Thread): def run(self): self.func1() self.func2() def func1(self): muxeA.acquire() print('%s搶到A鎖了'%self.name) muxeB.acquire() print('%s搶到B鎖了' % self.name) muxeB.release() muxeA.release() def func2(self): muxeB.acquire() print('%s搶到B鎖了' % self.name) time.sleep(2) muxeA.acquire() print('%s搶到A鎖了' % self.name) muxeA.release() muxeB.release() if __name__ == '__main__': for i in range(10): t=MyThread() t.start()
執行結果如下(沒有出現死鎖現象):
3、訊號量:
定義:就相當於多個互斥鎖:
具體例子如下:
from threading import Thread,Semaphore import time,random s=Semaphore(5) def task(name): s.acquire() print('%s號停車位正在停車'%name) time.sleep(random.randint(1,5)) s.release() if __name__ == '__main__': for i in range(10): t=Thread(target=task,args=(i,)) t.start()
比如:一些執行緒需要等待另一些執行緒完成才可以操作, 就類似傳送訊號一樣。
from threading import Thread,Event import time,random event=Event() def light(): print("紅燈") time.sleep(3) print('綠燈') event.set() #傳送訊號 def car(name): print('%s車正在等紅燈'%name) event.wait() #等待對方發訊號過來 print('%s車過綠燈'%name) if __name__ == '__main__': t=Thread(target=light) t.start() for i in range(10): t1=Thread(target=car,args=(i,)) t1.start()
池的概念:就是保證計算硬體的安全前提下,最大限度的利用計算機。
它降低執行效率,但是,保證了計算機硬體的安全。
注意: 池裡面原有的執行緒或程式是不會重複出現建立和銷燬的過程。
#執行緒池的建立: pool=ThreadPoolExecutor() #括號內為執行緒池中程式的個數,你可以自己設定,預設是5個,最大不會超過32個 ThreadPoolExecutor類中的引數max_workers就是池中執行緒數:初始設定程式碼如下: max_workers = min(32, (os.cpu_count() or 1) + 4) #程式池的建立: pool=ProcessPoolExecutor() #它的引數如下:os.cpu_count()表示電腦的CPU核數 self._max_workers = os.cpu_count() or 1 總結:關鍵程式碼如下: from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor pool=ProcessPoolExecutor() pool=ThreadPoolExecutor(5) res=pool.submit(task,i).add_done_callback(call_back)
程式/執行緒池的例子如下:
# -*-coding:utf-8 -*- from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import time,os # pool=ThreadPoolExecutor(5) pool=ProcessPoolExecutor() def call_back(n): print(">>:",n.result()) def task(n): print(n,os.getpid()) time.sleep(2) return n*n if __name__ == '__main__': # list_pool=[] for i in range(10): res=pool.submit(task,i).add_done_callback(call_back)
實質:就是一個思想,它是由程式設計師自己在程式碼層面上檢測IO操作,一旦遇到IO操作就會在程式碼級別上完成切換
注意:IO操作下的切換才是提高效率的,非IO操作下的切換會降低效率。
gevent模組的使用需要打猴子補丁,不然不會檢測到像time.sIeep()等O操作
#猴子補丁 from gevent import monkey monkey.patch_all()
具體例子如下:
# -*-coding:utf-8 -*- #猴子補丁 from gevent import monkey monkey.patch_all() from gevent import spawn import time def ha(): print('hahaha') time.sleep(2) print('hahaha') def xixi(): print('xixi') time.sleep(3) print('xixi') if __name__ == '__main__': start_time=time.time() g1=spawn(ha) g2=spawn(xixi) g1.join() g2.join() print(time.time()-start_time)
服務端例子如下:
1 # -*-coding:utf-8 -*- 2 #猴子補丁 3 from gevent import monkey;monkey.patch_all() 4 5 from gevent import spawn 6 import socket 7 8 def new_server(ip,addr): 9 server=socket.socket() 10 server.bind((ip,addr)) 11 server.listen(5) 12 while True: 13 conn,addr=server.accept() 14 spawn(connect,conn) 15 16 def connect(conn): 17 while True: 18 try: 19 data=conn.recv(1024) 20 print(data.decode()) 21 if len(data)==0:break 22 conn.send(data.upper()) 23 except Exception as e: 24 print(e) 25 break 26 if __name__ == '__main__': 27 g1=spawn(new_server,'localhost',8080) 28 g1.join()
客戶端程式碼如下:
1 # -*-coding:utf-8 -*- 2 import socket 3 from threading import Thread,current_thread 4 5 def new_client(): 6 c=socket.socket() 7 c.connect(('localhost',8080)) 8 while True: 9 data=('你好,我是%s'%current_thread().name) 10 c.send(data.encode()) 11 data1=c.recv(1024) 12 print(data) 13 14 if __name__ == '__main__': 15 for i in range(200): 16 t=Thread(target=new_client) 17 t.start()