threading 學習筆記

1、線程基礎python

一、線程狀態 app

二、線程互斥鎖同步控制 dom

多個線程須要修改同一共享數據時,須要進行同步控制,引入了鎖的概念。函數

 

 

 

a、同一時間可能有多個線程在鎖定池中,它們處於同步阻塞狀態競爭鎖定;post

b、同一時間只能有一個線程得到鎖定處於運行狀態。 ui

三、條件變量(線程通訊) spa

有的線程須要預備條件才能幹活。

 

2、threading:線程建立、啓動、睡眠、退出操作系統

一、方法一:將要執行的函數做爲參數傳遞給 threading.Thread() 線程

 1 # -*- coding:utf-8 -*- 
 2 import threading, time
 3 def func(n): 
 4     global count
 5     time.sleep(0.1)
 6     for i in range(n):
 7         count += 1
 8 if __name__==’__main__’: 
 9     count = 0
10     threads = []
11     for i in range(5):
12          threads.append(threading.Thread(target=func, args=(1000,)))
13     for t in threads:
14          t.start() 
15     time.sleep(5)
16     print(‘count:’,count)                    

以上例子建立了 5 個線程去執行 func 函數。得到的結果多是 5000,但也有時候會出現錯誤,解決方法請繼續閱 讀下文。
要點: 3d

  1. threading.Thread(target=func, args=(10,)):func 爲函數名,args 爲函數參數(必須以元組的形式傳遞 );

  2. t.start(): 啓動函數,等待操做系統調度;

c. 函數運行結束,線程也就結束;
d. time.sleep(): 線程進入睡眠,處於 IO 阻塞狀態。

一、方法二:繼承 threading.Thread()類,並重寫 run()

 

 1 # -*- coding:utf-8 -*- 
 2 import threading, time
 3 class myThread(threading.Thread): 
 4     def __init__(self, n):
 5           threading.Thread.__init__(self)
 6           self.myThread_n = n 
 7     def run(self):
 8           global count
 9           for i in range(self.myThread_n):
10                 count += 1
11 if __name__==’__main__’: 
12         count = 0
13         threads = []
14         for i in range(5):
15                 threads.append(myThread(1000))
16         for t in threads:
17                 t.start() 
18         time.sleep(5)
19         print(‘count:’,count)   

 

要點:
a. threading.Thread.__init__(self):回調父類方法。若是你重寫了__init__()方法,這一步是必須的,不然出錯。 

3、threading:線程同步鎖互斥控制

由於線程是亂序執行的,在某種狀況下上面的兩個例子,輸出的結果可能不是預期的值。

我將第 2 例的線程類修改下,讓問題更加突出,而後你每次運行的時候再把線程數也修改下,

並計算出預期結果和運行 結果對比。必定要多試幾回哦。 

1 class myThread(threading.Thread): 
2     def __init__(self, n):
3         threading.Thread.__init__(self)
4         self.myThread_n = n 
5     def run(self):
6         global count
7         for i in range(self.myThread_n):
8               __Temp = count time.sleep(0.0001)
9               count = __Temp + 1        

是否是輸出的結果和預期結果不一致啊,呵呵!由於多個線程都在同時操做同一個共享資源

,因此形成資源破壞。不過 咱們能夠經過同步鎖來解決這種問題: 

 1 # -*- coding:utf-8 -*-
 2 import threading, time
 3 class myThread(threading.Thread): 
 4     def __init__(self, n):
 5         threading.Thread.__init__(self)
 6         self.myThread_n = n 
 7     def run(self):
 8         global count
 9         for i in range(self.myThread_n):
10             if lock.acquire():
11                  __Temp = count
12                 time.sleep(0.0001) 
13                 count = __Temp + 1 
14                 lock.release()
15 if __name__==’__main__’: 
16     count = 0
17     lock = threading.Lock() #同步鎖
18     threads = []
19     for i in range(5):
20       
21         threads.append(myThread(1000)) for t in threads:
22     t.start() time.sleep(5)
23     print(‘count:’,count)            

 

要點:

  1. lock = threading.Lock():建立鎖;

  2. lock.acquire([timeount]):請求鎖定,若是設定了 timeout,則在超時後經過返回值能夠判斷是否獲得了鎖 , 

      從而能夠進行一些其餘的處理 ; c. lock.release():釋放鎖定。 

4、threading:線程死鎖和遞歸鎖

一、死鎖

a. 在線程間共享多個資源的時候,若是兩個線程分別佔有一部分資源而且同時等待對方的資源,

就會形成死鎖 , 由於系統判斷這部分資源都正在使用 ,全部這兩個線程在無外力做用下將一直

等待下去 。下面是一個死鎖的例 子: 

 1 # -*- coding:utf-8 -*- 
 2 import threading, time
 3 class myThread(threading.Thread):
 4      def doA(self):
 5             if lockA.acquire(): 
 6                   print(self.name,」got lockA.」) time.sleep(0.0001)
 7             if lockB.acquire():
 8                   print(self.name,」got lockB」)
 9                   lockB.release()
10             lockA.release()
11     def doB(self):
12             if lockB.acquire():
13                    print(self.name,」got lockB.」) 
14                    time.sleep(0.0001)
15                    if lockA.acquire():
16                          print(self.name,」got lockA」)
17                          lockA.release()
18                    lockB.release()
19      def run(self): 
20             self.doA() 
21             self.doB()
22 if __name__==’__main__’: 
23       lockA = threading.Lock() 
24       lockB = threading.Lock()
25       threads = []
26       for i in range(5):
27              threads.append(myThread()) 
28       for t in threads:
29            t.start()
30       for t in threads:
31            t.join() #等待線程結束,後面再講。    

 

b. 當一個線程已經得到了鎖,再此請求鎖也會出現死鎖,請看下面的例子: 

 1 # -*- coding:utf-8 -*- 
 2 import threading, time 
 3 import random
 4 class myThread(threading.Thread): 
 5     def toHex(self):
 6         global L
 7         if lock.acquire(1):
 8             for i in range(len(L)):
 9                 if type(L[i]) is int: L[i]=」{:X}」.format(L[i])
10             lock.release() 
11         else:
12             print(self.name,「錯誤,系統忙」) 
13     def run(self):
14         global L
15         if lock.acquire(1):
16             L.append(random.randint(0, 15)) 
17             self.toHex()
18             lock.release()
19         else: 
20             print(self.name,「錯誤,系統忙」)
21 if __name__==’__main__’: 
22         L = []
23         lock = threading.Lock()
24         threads = []
25         for i in range(5):
26             threads.append(myThread()) 
27         for t in threads:
28                 t.start()
29         for t in threads:
30                 t.join() #等待線程結束,後面再講。            

二、遞歸鎖(也稱可重入鎖)

    上一例子的死鎖,咱們能夠用遞歸鎖解決:
 1 #lock = threading.Lock() 註釋掉此行,並加入下行。 2 lock = threading.RLock() 

爲了支持在同一線程中屢次請求同一資源 ,python 提供了「可重入鎖」:threading.RLock。RLock 內部維護着一個 Lock 和一個 counter 變量,counter 記錄了 acquire 的次數,從而使得資源能夠被屢次 require。直到一個線程全部的 acquire 都 被 release,其餘的線程才能得到資源。

    遞歸鎖通常應用於複雜的邏輯。

5、threading:條件變量同步

有一類線程須要知足條件以後纔可以繼續執行, Python 提供了 threading.Condition 對象用於條件變量線程的支持,它除 了能提供 RLock()或 Lock()的方法外,還提供了 wait()、notify()、notifyAll()方法。

lock_con = threading.Condition([Lock/Rlock]) :鎖是可選選項,不傳人鎖,對象自動建立一個 RLock()。 wait():條件不知足時調用,線程會釋放鎖並進入等待阻塞; notify():條件創造後調用,通知等待池激活一個線程;

#lock = threading.Lock() 註釋掉此行,並加入下行。 lock = threading.RLock()

notifyAll():條件創造後調用,通知等待池激活全部線程。 

相關文章
相關標籤/搜索