Python多線程學習(中)

  今天接着寫多線程,最近幾天一直在看多線程,可是書上的例子太難看了(可能我天生愚笨吧~_~),看了很久才搞懂,我看了兩本書才搞明白書上的例子,因此你們在看書學習看不懂的時候,推薦多看幾本同樣知識點的書,在網上多看教程,輔助學習。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()

 

以上就是關於多線程的鎖,信號量,條件變量,有不對的地方還望多指教。 

相關文章
相關標籤/搜索