python互斥鎖

互斥鎖

進程之間數據隔離, 可是多個進程能夠共享同一塊數據,好比共享同一套文件系統,因此訪問同一個文件,或同一個打印終端,是沒有問題的,而共享帶來的是競爭,競爭帶來的結果就是錯亂,以下python

from multiprocessing import Process
import time
import os

def task(name):
    print('%s 上廁所 [%s]' %(name ,os.getpid()))
    time.sleep(1)
    print('%s 上完廁所 [%s]' %(name ,os.getpid()))


if __name__ == '__main__':
    for i in range(3):
        p=Process(target=task, args=('進程%s' %i,))
        p.start()

----------輸出結果
進程2 上廁所 [8076]
進程0 上廁所 [5176]
進程1 上廁所 [2100]
進程2 上完廁所 [8076]
進程0 上完廁所 [5176]
進程1 上完廁所 [2100]

如何控制,就是加鎖處理。而互斥鎖的意思就是互相排斥,若是把多個進程比喻爲多我的,互斥鎖的工做原理就是多我的都要去爭搶同一個資源:衛生間,一我的搶到衛生間後上一把鎖,數據庫

其餘人都要等着,等到這個完成任務後釋放鎖,其餘人才有可能有一個搶到......因此互斥鎖的原理,就是把併發改爲串行,下降了效率,但保證了數據安全不錯亂  json

from multiprocessing import Process, Lock
import time
import os

def task(name,mutex):
    mutex.acquire()
    print('%s 上廁所 [%s]' %(name ,os.getpid()))
    time.sleep(1)
    print('%s 上完廁所 [%s]' %(name ,os.getpid()))
    mutex.release()


if __name__ == '__main__':
    mutex = Lock()
    for i in range(3):
        p=Process(target=task, args=('進程%s' %i,mutex))
        p.start()

----輸出結果
進程0 上廁所 [5340]
進程0 上完廁所 [5340]
進程1 上廁所 [7796]
進程1 上完廁所 [7796]
進程2 上廁所 [7860]
進程2 上完廁所 [7860]

  

模擬搶票練習

多個進程共享同一文件,咱們能夠把文件當數據庫,用多個進程模擬多我的執行搶票任務安全

# db.txt
# {"count": 2}

from multiprocessing import Process,Lock
import json
import time
import os

def query_ticket(name):
    time.sleep(1)
    with open('db.txt','r',encoding="utf-8") as f:
        d = json.load(f)
        print('[%s] 查看到剩餘票數 [%s]'% (name, d['count']))

def buy_ticket(name):
    time.sleep(1)
    with open('db.txt','r', encoding="utf-8") as f:
        d = json.load(f)
        if d.get('count') >0 :
            d['count'] -= 1
            time.sleep(1)
            json.dump(d, open('db.txt','w',encoding='utf-8'))
            print('<%s> 購票成功' % name)
        else:
            print('沒有多餘的票,<%s> 購票失敗' % name)

def task(name,mutex):
    query_ticket(name)
    mutex.acquire()
    buy_ticket(name)
    mutex.release()

if __name__ == '__main__':
    mutex = Lock()
    print('開始搶票了……')
    for i in range(5):
        p = Process(target=task, args=('進程%s' %i,mutex))
        p.start()

  

 輸出結果併發

開始搶票了……
[進程0] 查看到剩餘票數 [2]
[進程1] 查看到剩餘票數 [2]
[進程2] 查看到剩餘票數 [2]
[進程4] 查看到剩餘票數 [2]
[進程3] 查看到剩餘票數 [2]
<進程0> 購票成功
<進程1> 購票成功
沒有多餘的票,<進程2> 購票失敗
沒有多餘的票,<進程4> 購票失敗
沒有多餘的票,<進程3> 購票失敗

  

  

互斥鎖與join

使用join能夠將併發變成串行,互斥鎖的原理也是將併發變成串行,那咱們直接使用join就能夠了啊,爲什麼還要互斥鎖函數

from multiprocessing import Process,Lock
import json
import time

def query_ticket(name):
    time.sleep(1)
    with open('db.txt','r',encoding="utf-8") as f:
        d = json.load(f)
        print('[%s] 查看到剩餘票數 [%s]'% (name, d['count']))


def buy_ticket(name):
    time.sleep(1)
    with open('db.txt','r', encoding="utf-8") as f:
        d = json.load(f)
        if d.get('count') > 0 :
            d['count'] -= 1
            time.sleep(1)
            json.dump(d, open('db.txt','w',encoding='utf-8'))
            print('<%s> 購票成功' % name)
        else:
            print('沒有多餘的票,<%s> 購票失敗' % name)

def task(name):
    query_ticket(name)
    buy_ticket(name)

if __name__ == '__main__':
    print('開始搶票了……')
    for i in range(5):
        p = Process(target=task, args=('進程%s' % i,))
        p.start()
        p.join()

----------------輸出結果--------------
開始搶票了……
[進程0] 查看到剩餘票數 [2]
<進程0> 購票成功
[進程1] 查看到剩餘票數 [1]
<進程1> 購票成功
[進程2] 查看到剩餘票數 [0]
沒有多餘的票,<進程2> 購票失敗
[進程3] 查看到剩餘票數 [0]
沒有多餘的票,<進程3> 購票失敗
[進程4] 查看到剩餘票數 [0]
沒有多餘的票,<進程4> 購票失敗

發現使用join將併發改爲穿行,確實能保證數據安全,但問題是連查票操做也變成只能一個一我的去查了,很明顯你們查票時應該是併發地去查詢而無需考慮數據準確與否,ui

此時join與互斥鎖的區別就顯而易見了,join是將一個任務總體串行,而互斥鎖的好處則是能夠將一個任務中的某一段代碼串行,好比只讓task函數中的buy_ticket任務串行spa

def task(name,mutex):
    query_ticket(name)
    mutex.acquire()
    buy_ticket(name)
    mutex.release()

總結

加鎖能夠保證多個進程修改同一塊數據時,同一時間只能有一個任務能夠進行修改,即串行地修改,沒錯,速度是慢了,但犧牲了速度卻保證了數據安全。blog

雖然能夠用文件共享數據實現進程間通訊,但問題是:隊列

一、效率低(共享數據基於文件,而文件是硬盤上的數據)

二、須要本身加鎖處理

所以咱們最好找尋一種解決方案可以兼顧:

一、效率高(多個進程共享一塊內存的數據)

二、幫咱們處理好鎖問題。

這就是mutiprocessing模塊爲咱們提供的基於消息的IPC通訊機制:隊列和管道。

隊列和管道都是將數據存放於內存中,而隊列又是基於(管道+鎖)實現的,可讓咱們從複雜的鎖問題中解脫出來,於是隊列纔是進程間通訊的最佳選擇。

相關文章
相關標籤/搜索