今天接着寫多線程,最近幾天一直在看多線程,可是書上的例子太難看了(可能我天生愚笨吧~_~),看了很久才搞懂,我看了兩本書才搞明白書上的例子,因此你們在看書學習看不懂的時候,推薦多看幾本同樣知識點的書,在網上多看教程,輔助學習。python
下面開始介紹鎖和條件變量。多線程
一。「鎖」app
鎖是指在運行程序時,對於須要訪問共享資源的多線程程序,爲防止I/O密集型操做形成結果發生錯誤。dom
使用鎖的方法: import threading函數
引入鎖 lock = threading.Lock()學習
添加鎖 lock.acquire()ui
對臨界資源進行訪問的代碼spa
釋放鎖 lock.release()線程
假設對數字進行迭代輸出,在不加鎖的狀況下,會致使輸出全爲15,加鎖後是1,2,3,4.。。。。。13,14,15,最後輸出‘all done'code
對於添加鎖,添加鎖後就只能一個線程對公共資源進行訪問,因此在執行時速度會變慢,由於執行時等同於同步運行。
示例一代碼:
#!/usr/bin/env python3.6 # -*- coding: utf-8 -*- #導入模 import threading import time from atexit import register import random lock = threading.Lock() a = 0 def print_sum(): global a lock.acquire() a += 1 time.sleep(1) print(str(a)) lock.release() def main(): th_list = [] for x in range(15): t = threading.Thread(target=print_sum,args=()) th_list.append(t) for x in th_list: x.start() @register def exit(): print('all done') if __name__ == '__main__': main()
二。條件變量
對於條件變量,能夠添加一個判斷條件,若是符合條件就執行,不然等待。
導入模塊 from threading import Condition
該模塊有acquirre()和release(),在不符合條件時,調用.wait(),此時線程就會掛起,調用.notify() 或.notify_all()來激活線程,再進行條件判斷。
以消費--生產問題來進行對條件變量討論。建立一個產品類,一個消費者類,一個生產者類,消費者有五個線程,生產者有一個線程,生產者不斷生產,消費者持續消費,不會存在無限生產消費不完的問題,可是中止程序須要手動完成。
代碼:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import threading import time import random #條件變量,消費者和生產者 #產品類 class Chan_pin(): def __init__(self): self.count = 0 #消費產品 def xiao_fei(self): self.count -= 1 #生產產品 def sheng_chan(self): self.count += 1 #判斷產品是否爲空 def pan_duan(self): return not self.count pass #生產類 class Sheng_chans(threading.Thread): def __init__(self,tiao_jian,chan_pin): super().__init__() self.tiao_jian = tiao_jian self.chan_pin = chan_pin def run(self): while True: self.tiao_jian.acquire() self.chan_pin.sheng_chan() print('已生產的產品數:%s' % self.chan_pin.count) self.tiao_jian.notify_all() self.tiao_jian.release() time.sleep(random.random()) pass #建立消費類 class Xiao_fei(threading.Thread): def __init__(self,chan_pin,tiao_jian): super().__init__() self.tiao_jian = tiao_jian self.chan_pin = chan_pin #重構run函數 def run(self): while True: self.tiao_jian.acquire() time.sleep(random.randint(2,5)) if self.chan_pin.pan_duan(): self.tiao_jian.wait() print('%s產品沒了,請等待。。。' % threading.current_thread().name) else: self.chan_pin.xiao_fei() print('%s已消費,現剩餘產品:%s' % (threading.current_thread().name,self.chan_pin.count)) self.tiao_jian.notify_all() self.tiao_jian.release() pass #建立實例。 def main(): tiao_jian = threading.Condition() chan_pin = Chan_pin() t1 = Sheng_chans(tiao_jian,chan_pin) t1.start() time.sleep(5) #t1.join() for x in range(5): t2 = Xiao_fei(chan_pin,tiao_jian) t2.start() print(threading.active_count()) print(threading.enumerate()) print(threading.enumerate()[-2].is_alive()) #t2.join() #運行 if __name__ == '__main__': main()
三。信號量
信號量容許添加指定個數的線程對公共資源進行訪問。
對於信號量有兩個模塊可用,分別是:Semaphore和BoundedSemaphore 前一個模塊比第二個有一個缺點,第一個在進行調用.release()時,添加數超過設定數時不會報錯,而第二個會進行報錯。
本文章主要對第二個進行介紹。
該模塊有兩個方法, .acquire()和.release() 在調用.acquire()時會減一,當減到0時,會中止線程運行,進入等待;調用.release()時會加一。
調用方法:
num = 5 #表示只容許5個線程對公共資源進行訪問。
a = BoundedSemaphore(num)
a.acquire()
要執行的代碼
a.release()
下面是示例代碼:
1 #!/usr/bin/env python3.6 2 # -*- coding: utf-8 -*- 3 #導入模 4 import threading 5 import time 6 from atexit import register 7 8 9 #要操做的公共資源,設置一個列表,多個線程對列表進行訪問,輸出列表內容。 10 11 num = 3 12 a = threading.BoundedSemaphore(num) 13 #建立一個輸出內容的函數 14 def print_list(list): 15 a.acquire() 16 p = threading.current_thread().name 17 if a.acquire(False): 18 print('%s : 不能運行' % p) 19 else: 20 print('%s:%s' % (p,list)) 21 a.release() 22 23 #繼承線程類 24 class New_thread(threading.Thread): 25 def __init__(self,han_name,han_can): 26 super().__init__() 27 self.han_name = han_name #函數名 28 self.han_can = han_can #要傳入函數的參數 29 def run(self): 30 self.han_name(self.han_can) 31 pass 32 33 # 34 def main(): 35 list_1 = ['aaaa', 'bbbb', 'cccc', 'dddd', 'eeee', 'ffff'] 36 #線程列表 37 thread_list = [] 38 #建立十個線程 39 for x in range(5): 40 t = New_thread(print_list,list_1) 41 thread_list.append(t) 42 for x in thread_list: 43 x.start() 44 #print(thread_list) 45 46 #建立回調函數。 47 @register 48 def exit(): 49 print('all done') 50 51 if __name__ == '__main__': 52 main()
以上就是關於多線程的鎖,信號量,條件變量,有不對的地方還望多指教。