1. 程式人生 > >鎖,信號量 ,事件 Event模塊

鎖,信號量 ,事件 Event模塊

搶票 time 等待 數量 出現 money nbsp %s tick

1. 鎖

Lock模塊: 保證一段代碼,在同一時刻只能被一個進程執行.
    lock = Lock()   創造了一把鎖
    acquire()    獲取鎖的鑰匙
    release()    歸還這把鎖的鑰匙
  ps: 多進程的數據的不安全性: 當多個進程共享一段數據的時候, 數據會出現不安全的現象, 需要加鎖, 來維護數據的安全性.

 例: 

  搶票:

搶票分析: 
      客戶可以同一時間訪問服務器,並且訪問到 同一個余票數
     當客戶發出購買請求, 服務器必須進行同步處理, 一個一個來. 

from multiprocessing import Process,Lock
import time

def check(i):
    with open(‘余票‘) as f:
        con = f.read()
    print(‘第%s個人查到余票還剩%s張‘%(i,con))

def buy_ticket(i,l):
    l.acquire()# 拿鑰匙,鎖門
    with open(‘余票‘) as f:
        con = int(f.read())
        time.sleep(0.1)
    if con > 0:
        print(‘\033[31m 第%s個人買到票了\033[0m‘%i)
        con -= 1
    else:
        print(‘\033[32m 第%s個人沒有買到票\033[0m‘%i)
    time.sleep(0.1)# 是指 買完票後,把余票數量重寫寫入數據庫的時間延遲
    with open(‘余票‘,‘w‘) as f:
        f.write(str(con))
    l.release()# 還鑰匙,開門

if __name__ == ‘__main__‘:
    l = Lock()
    for i in range(10):
        p_ch = Process(target=check,args=(i+1,))
        p_ch.start()
    for i in range(10):
        p_buy = Process(target=buy_ticket,args=(i+1,l))
        p_buy.start()

   銀行同時取錢.存錢:

from multiprocessing import Process,Value,Lock
import time


def get_money(num,l):# 取錢
    l.acquire()# 拿走鑰匙,鎖上門,不允許其他人進屋
    for i in range(100):
        num.value -= 1
        print(num.value)
        time.sleep(0.01)
    l.release()# 還鑰匙,打開門,允許其他人進屋

def put_money(num,l):# 存錢
    l.acquire()
    for i in range(100):
        num.value += 1
        print(num.value)
        time.sleep(0.01)
    l.release()

if __name__ == ‘__main__‘:
    num = Value(‘i‘,100)
    l = Lock()
    p = Process(target=get_money,args=(num,l))
    p.start()
    p1 = Process(target=put_money, args=(num,l))
    p1.start()
    p.join()
    p1.join()
    print(num.value)

  

2, 信號量

Semaphore模塊: 多把鑰匙 對應一把鎖

    本質就是: lock+count 計數 來實現的

sem = Semaphore(n)
n : 是指初始化一把鎖配幾把鑰匙,一個int型
拿鑰匙,鎖門 l.acquire()
還鑰匙,開門 l.release()
信號量機制比鎖機制多了一個計數器,這個計數器是用來記錄當前剩余幾把鑰匙的。
當計數器為0時,表示沒有鑰匙了,此時acquire()處於阻塞。
對於計數器來說,每acquire一次,計數器內部就減1,release一次,計數器就加1
例:
  發廊:
from multiprocessing import Process,Semaphore
import time
import random

def func(i,sem):
    sem.acquire()
    print(‘\033[31m 第%s個人進入小黑屋,拿了鑰匙鎖上門\033[0m‘ % i)
    time.sleep(random.randint(3,5))
    print(‘\033[32m 第%s個人出去小黑屋,還了鑰匙打開門 \033[0m‘ % i)
    sem.release()

if __name__ == ‘__main__‘:
    sem=Semaphore(5)# 初始化了一把鎖5把鑰匙,也就是說允許5個人同時進入小黑屋
    # 之後其他人必須等待,等有人從小黑屋出來,還了鑰匙,才能允許後邊的人進入
    for i in range(20):
        p=Process(target=func,args=(i,sem,))
        p.start()

3, 事件 Event模塊:

 標誌:在 事件創立之初,標誌默認為False

 wait(timeout=None) 等待 有一個關鍵字參數 timeout(超時) 以秒為單位.

e = Event()
# e.set() #將is_set()設為True
# e.clear() # 將is_set()設為False
# e.wait() #判斷is_set的bool值,如果bool為True,則非阻塞,bool值為False,則阻塞
# e.is_set() # 標識
# 事件是通過is_set()的bool值,去標識e.wait() 的阻塞狀態
# 當is_set()的bool值為False時,e.wait()是阻塞狀態
# 當is_set()的bool值為True時,e.wait()是非阻塞狀態
# 當使用set()時,是把is_set的bool變為True
# 當使用clear()時,是把is_set的bool變為False
例:  
信號燈:
from multiprocessing import Process,Event
import time
import random

def tra(e):
    ‘‘‘信號燈函數‘‘‘
    # e.set()
    # print(‘\033[32m 綠燈亮! \033[0m‘)
    while 1:# 紅綠燈得一直亮著,要麽是紅燈要麽是綠燈
        if e.is_set():# True,代表綠燈亮,那麽此時代表可以過車
            time.sleep(5)# 所以在這讓燈等5秒鐘,這段時間讓車過
            print(‘\033[31m 紅燈亮! \033[0m‘)# 綠燈亮了5秒後應該提示到紅燈亮
            e.clear()# 把is_set設置為False
        else:
            time.sleep(5)# 此時代表紅燈亮了,此時應該紅燈亮5秒,在此等5秒
            print(‘\033[32m 綠燈亮! \033[0m‘)# 紅的亮夠5秒後,該綠燈亮了
            e.set()# 將is_set設置為True

def Car(i,e):
    e.wait()# 車等在紅綠燈,此時要看是紅燈還是綠燈,如果is_set為True就是綠燈,此時可以過車
    print(‘第%s輛車過去了‘%i)

if __name__ == ‘__main__‘:
    e = Event()
    triff_light = Process(target=tra,args=(e,))# 信號燈的進程
    triff_light.start()
    for i in range(50):# 描述50輛車的進程
        if i % 3 == 0:
            time.sleep(2)
        car = Process(target=Car,args=(i+1,e,))
        car.start()

  

鎖,信號量 ,事件 Event模塊