Python學習之路併發編程--信號量、事件、隊列及生產消費模型

1. 信號量  安全

  對於多進程來講,多個進程同時修改數據,就可能出現安全隱患,因此引入了鎖,這一機制,但鎖只能有一把來控制一個的開關,當你須要幾把鎖的時候,就可能用到信號量的概念。他是用了鎖的原理,內置了一個計數器,在同一時內,只能有指定數量的進程來執行某一段被控制的代碼。dom

import time,random
from multiprocessing import Process,Semaphore

def singing(i,sem):
    '''
    :param i: 隨機生成20個數的值
    :param sem:生成的信號量
    :return:None
    '''
    sem.acquire()#得到鎖
    print('%s is coming '%i)
    time.sleep(random.randint(10,20))#隨機在10秒至20秒中停頓
    print('%s is going out'%i)
    sem.release()#釋放鎖

if __name__ == '__main__':
    sem = Semaphore(4)#生成4個鎖
    for i in range(20):
        p = Process(target=singing,args=(i,sem))
        p.start()

 

2. 事件函數

  事件是經過一個信號來控制多個進程的同時執行或阻塞,當一個事件被建立的時候默認是阻塞狀態,但不影響進程的執行,當遇到 even.wait() 方法時,纔會阻塞。ui

# set 和 clear
#      分別用來修改一個事件的狀態 True或者False
# is_set 用來查看一個事件的狀態
# wait 是依據事件的狀態來決定本身是否在wait處阻塞
#      False阻塞 True不阻塞

  下面是一個紅綠燈的問題。spa

import time
import random
from multiprocessing import Event,Process

def cars(e,i):
    '''
    一個判斷車是否經過的函數
    :param e: 傳入一個事件
    :param i: 生成的車幾
    :return: None
    '''
    if not e.is_set():
        print('\033[0;31;40mcar %s 在等待~\033[0m'%i)
        e.wait()
    print('\033[32;40mcar %s 經過~\033[0m'%i)

def light(e):
    '''
    控制紅綠燈的切換
    :param e: 傳入事件
    :return: None
    '''
    while True:
        if e.is_set():
            e.clear()
            print('\033[31m紅燈亮了\033[0m')
            time.sleep(3)
        else:
            e.set()
            print('\033[32m綠燈亮了\033[0m')
            time.sleep(5)

if __name__ == '__main__':
    e = Event()
    traffic = Process(target=light,args=(e,))
    traffic.start()
    time.sleep(1)
    for i in range(random.randint(5,10)):
        car = Process(target=cars,args=(e,i))
        car.start()
        time.sleep(random.randint(1,3))

 

3. 隊列code

  隊列 Queue 中只有少數幾個方法,blog

    # put  當隊列滿的時候阻塞等待隊列有空位置
    # get  當隊列空的時候阻塞等待隊列有數據
    # full empty 不徹底準確

  full 和 empty 不許一緣由在於,若是隊列回答主程序時,同時進程又對隊列進行了操做,這個就會形成數據的錯誤。隊列

 

4. 用 JoinableQueue 來處理生產者和消費者模型進程

import time
import random
from multiprocessing import Process,JoinableQueue


def producer(name,food,q):
    for i in range(4):
        time.sleep(random.randint(1,3))
        f = '%s生產了%s%s'%(name,food,i)
        print(f)
        q.put(f)
    q.join()    # 阻塞  直到一個隊列中的全部數據 所有被處理完畢

def consumer(q,name):
    while True:
        food = q.get()
        print('\033[31m%s消費了%s\033[0m' % (name,food))
        time.sleep(random.randint(1,3))
        q.task_done()     # count - 1

if __name__  == '__main__':
    q = JoinableQueue(20)
    p1 = Process(target=producer,args=('eli','dumpling',q))
    p2 = Process(target=producer, args=('tom','noodle', q))
    c1 = Process(target=consumer, args=(q,'mike'))
    c2 = Process(target=consumer, args=(q,'johan'))
    p1.start()
    p2.start()

    c1.daemon = True   # 設置爲守護進程 主進程中的代碼執行完畢以後,子進程自動結束
    c2.daemon = True

    c1.start()
    c2.start()
    p1.join()
    p2.join()      # 感知一個進程的結束

  以爲最好的點就是用到了守護進程(當主進程的程序執行完成時,子進程也隨之結束)。事件

相關文章
相關標籤/搜索