python-day36--並發編程之多線程
阿新 • • 發佈:2017-08-30
其他 過程 連接 sleep print font 並發編程 name als
十三、死鎖、遞歸鎖
1.所謂死鎖: 是指兩個或兩個以上的進程或線程在執行過程中,因爭奪資源而造成的一種互相等待的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程,如下就是死鎖
1 from threading import Lock,Thread 2 import time 3 mutexB=Lock() 4 mutexA=Lock() 5 class MyThread(Thread): 6 def run(self): 7 self.f1() 8 self.f2()View Code9 10 def f1(self): 11 mutexA.acquire() 12 print(‘%s拿到了A鎖‘ %self.name) 13 mutexB.acquire() 14 print(‘%s拿到了B鎖‘ %self.name) 15 mutexB.release() 16 mutexA.release() 17 18 def f2(self): 19 mutexB.acquire() 20 print(‘%s拿到了B鎖‘ %self.name)21 time.sleep(1) 22 mutexA.acquire() 23 print(‘%s拿到了A鎖‘ %self.name) 24 mutexA.release() 25 mutexB.release() 26 27 if __name__ == ‘__main__‘: 28 for i in range(10): 29 t=MyThread() 30 t.start() 31 32 # 結果 33 # Thread-1拿到了A鎖 34 # Thread-1拿到了B鎖35 # Thread-1拿到了B鎖 36 # Thread-2拿到了A鎖 37 。。。。 卡住了
2.解決方法,遞歸鎖,在Python中為了支持在同一線程中多次請求同一資源,python提供了可重入鎖RLock。
這個RLock內部維護著一個Lock和一個counter變量,counter記錄了acquire的次數,從而使得資源可以被多次require。直到一個線程所有的acquire都被release,其他的線程才能獲得資源。上面的例子如果使用RLock代替Lock,則不會發生死鎖:
1 from threading import Thread,RLock 2 import time 3 mutexB=mutexA=RLock() 4 class MyThread(Thread): 5 def run(self): 6 self.f1() 7 self.f2() 8 9 def f1(self): 10 mutexA.acquire() 11 print(‘\033[32m%s 拿到A鎖‘ %self.name) 12 mutexB.acquire() 13 print(‘\033[45m%s 拿到B鎖‘ %self.name) 14 mutexB.release() 15 mutexA.release() 16 17 def f2(self): 18 mutexB.acquire() 19 print(‘\033[32m%s 拿到B鎖‘ %self.name) 20 time.sleep(1) 21 mutexA.acquire() 22 print(‘\033[45m%s 拿到A鎖‘ %self.name) 23 mutexA.release() 24 mutexB.release() 25 26 if __name__ == ‘__main__‘: 27 for i in range(2): 28 t=MyThread() 29 t.start() 30 31 # 結果: 32 # Thread-1 拿到A鎖 33 # Thread-1 拿到B鎖 34 # Thread-1 拿到B鎖 35 # Thread-1 拿到A鎖 36 # Thread-2 拿到A鎖 37 # Thread-2 拿到B鎖 38 # Thread-2 拿到B鎖 39 # Thread-2 拿到A鎖View Code
十四、信號量Semaphore
Semaphore管理一個內置的計數器,
每當調用acquire()時內置計數器-1;
調用release() 時內置計數器+1;
計數器不能小於0;當計數器為0時,acquire()將阻塞線程直到其他線程調用release()。
1 from threading import Thread,Semaphore,currentThread 2 import time,random 3 sm=Semaphore(5) #限制最大連接數為5 4 def task(): 5 sm.acquire() 6 print(‘%s 上廁所‘ %currentThread().getName()) 7 time.sleep(random.randint(1,3)) 8 print(‘%s 走了‘ %currentThread().getName()) 9 sm.release() 10 if __name__ == ‘__main__‘: 11 for i in range(20): 12 t=Thread(target=task) 13 t.start()View Code
與進程池是完全不同的概念,進程池Pool(4),最大只能產生4個進程,而且從頭到尾都只是這 四個進程,不會產生新的,而信號量是產生一堆線程/進程
十五、Event事件
1 event.isSet():返回event的狀態值; 2 3 event.wait():如果 event.isSet()==False將阻塞線程; 4 5 event.set(): 設置event的狀態值為True,所有阻塞池的線程激活進入就緒狀態, 等待操作系統調度; 6 7 event.clear():恢復event的狀態值為False。
1 from threading import Thread,Event,currentThread 2 import time 3 e=Event() 4 5 def traffic_lights(): 6 time.sleep(5) 7 e.set() 8 9 def car(): 10 print(‘\033[45m%s 等‘ %currentThread().getName()) 11 e.wait() 12 print(‘\033[45m%s 跑‘ %currentThread().getName()) 13 14 15 if __name__ == ‘__main__‘: 16 for i in range(10): 17 t=Thread(target=car) 18 t.start() 19 traffic_thread=Thread(target=traffic_lights) 20 traffic_thread.start()例子
1 from threading import Thread,Event,currentThread 2 import time 3 e=Event() 4 def conn_mysql(): 5 count=1 6 while not e.is_set(): 7 if count > 3: 8 raise ConnectionError(‘嘗試鏈接的次數過多‘) 9 print(‘\033[45m%s 第%s次嘗試‘ %(currentThread().getName(),count)) 10 e.wait(timeout=1) 11 count+=1 12 print(‘\033[45m%s 開始鏈接‘ %currentThread().getName()) 13 14 def check_mysql(): 15 print(‘\033[45m%s 檢測mysql...‘ %currentThread().getName()) 16 time.sleep(4) #超時了 17 e.set() 18 if __name__ == ‘__main__‘: 19 t=Thread(target=check_mysql) 20 t.start() 21 for i in range(3): 22 t=Thread(target=conn_mysql) 23 t.start()重要的例子
十六、定時器
1 from threading import Timer 2 3 def hello(n): 4 print("hello, world",n) 5 6 t = Timer(3, hello,args=(123,)) #3秒後運行hello函數, 可以傳參數 7 t.start()View Code
十七、線程queue
queue隊列 :使用import queue,用法與進程Queue一樣
queue.Queue
#先進先出 #隊列
1 import queue 2 3 q=queue.Queue() 4 q.put(‘first‘) 5 q.put(‘second‘) 6 q.put(‘third‘) 7 8 print(q.get()) 9 print(q.get()) 10 print(q.get()) 11 ‘‘‘ 12 結果(先進先出): 13 first 14 second 15 third 16 ‘‘‘View Code
queue.LifoQueue
#last in fisrt out #堆棧
1 import queue 2 3 q=queue.LifoQueue() 4 q.put(‘first‘) 5 q.put(‘second‘) 6 q.put(‘third‘) 7 8 print(q.get()) 9 print(q.get()) 10 print(q.get()) 11 ‘‘‘ 12 結果(後進先出): 13 third 14 second 15 first 16 ‘‘‘View Code
queue.PriorityQueue
#存儲數據時可設置優先級的隊列
1 import queue 2 3 q=queue.PriorityQueue() 4 #put進入一個元組,元組的第一個元素是優先級(通常是數字,也可以是非數字之間的比較),數字越小優先級越高 5 q.put((20,‘a‘)) 6 q.put((10,‘b‘)) 7 q.put((30,‘c‘)) 8 9 print(q.get()) 10 print(q.get()) 11 print(q.get()) 12 ‘‘‘ 13 結果(數字越小優先級越高,優先級高的優先出隊): 14 (10, ‘b‘) 15 (20, ‘a‘) 16 (30, ‘c‘) 17 ‘‘‘View Code
python-day36--並發編程之多線程