淺談線程鎖和進程鎖


​ 在python的多線程和多進程中,當我們需要對多線程或多進程的共享資源或對象進行修改操作時,往往會出現因cpu隨機調度而導致結果和我們預期不一致的問題,

線程舉例:

from threading import Thread,Lock

x = 0
def task():
    global x
    for i in range(200000):
        x = x+1
'''
假設
t1 的 x剛拿到0 保存狀態 就被切了
t2 的 x拿到0 進行+1       1
t1 又獲得運行了  x = 0  +1  1
思考:一共加了幾次1? 加了兩次1 真實運算出來的數字本來應該+2 實際只+1
這就產生了數據安全問題.
'''        


if __name__ == '__main__':
    t1 = Thread(target=task)
    t2 = Thread(target=task)
    t3 = Thread(target=task)
    t1.start()
    t2.start()
    t3.start()
    t1.join()
    t2.join()
    t3.join()
    print(x)

479261

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

def search():
    time.sleep(1) # 模擬網絡io
    with open('db.txt',mode='rt',encoding='utf-8') as f:
        res = json.load(f)
        print(f'還剩{res["count"]}')

def get():
    with open('db.txt',mode='rt',encoding='utf-8') as f:
        res = json.load(f)
    time.sleep(1) # 模擬網絡io
    if res['count'] > 0:
        res['count'] -= 1
        with open('db.txt',mode='wt',encoding='utf-8') as f:
            json.dump(res,f)
            print(f'進程{os.getpid()} 搶票成功')
        time.sleep(1.5) # 模擬網絡io
    else:
        print('票已經售空啦!!!!!!!!!!!')

def task():
    search()
    get()

if __name__ == '__main__':

    for i in range(5):
        p = Process(target=task)
        p.start()

還剩1
還剩1
還剩1
還剩1
還剩1
進程6292 搶票成功
進程10604 搶票成功
進程19280 搶票成功
進程272 搶票成功
進程12272 搶票成功

這時就需要對線程或者進程加鎖,以保證一個線程或進程在對共享對象進行修改時,其他的線程或進程無法訪問這個對象,直至獲取鎖的線程的操作執行完畢后釋放鎖。所以,鎖在多線程和多進程中起到一個同步的作用,以保護每個線程和進程必要操作的完整執行。

#線程鎖
from threading import Thread,Lock

x = 0
mutex = Lock()
def task():
    global x
    mutex.acquire()
    for i in range(200000):
        x = x+1

    mutex.release()

if __name__ == '__main__':
    t1 = Thread(target=task)
    t2 = Thread(target=task)
    t3 = Thread(target=task)
    t1.start()
    t2.start()
    t3.start()
    t1.join()
    t2.join()
    t3.join()
    print(x)

600000

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

def search():
    time.sleep(1) # 模擬網絡io
    with open('db.txt',mode='rt',encoding='utf-8') as f:
        res = json.load(f)
        print(f'還剩{res["count"]}')

def get():
    with open('db.txt',mode='rt',encoding='utf-8') as f:
        res = json.load(f)
        # print(f'還剩{res["count"]}')
    time.sleep(1) # 模擬網絡io
    if res['count'] > 0:
        res['count'] -= 1
        with open('db.txt',mode='wt',encoding='utf-8') as f:
            json.dump(res,f)
            print(f'進程{os.getpid()} 搶票成功')
        time.sleep(1.5) # 模擬網絡io
    else:
        print('票已經售空啦!!!!!!!!!!!')

def task(lock):
    search()

    # 鎖住
    lock.acquire()
    get()
    lock.release()
    # 釋放鎖頭

if __name__ == '__main__':
    lock = Lock() # 寫在主進程是為了讓子進程拿到同一把鎖.
    for i in range(15):
        p = Process(target=task,args=(lock,))
        p.start()
        # p.join()

    #  進程鎖 是把鎖住的代碼變成了串行
    #  join 是把所有的子進程變成了串行


# 為了保證數據的安全,串行犧牲掉效率.

還剩1
還剩1
還剩1
還剩1
還剩1
進程16868 搶票成功
票已經售空啦!!!!!!!!!!!
票已經售空啦!!!!!!!!!!!
票已經售空啦!!!!!!!!!!!
票已經售空啦!!!!!!!!!!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM