1. 程式人生 > >python-day36--並發編程之多線程

python-day36--並發編程之多線程

其他 過程 連接 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()
9 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 。。。。 卡住了
View Code

  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--並發編程之多線程