1. 程式人生 > >Python學習筆記--執行緒鎖

Python學習筆記--執行緒鎖

這裡寫圖片描述
如果你想啟動python的多執行緒對一個數據進行累加的操作,如果在py2上你多執行幾次會發現少加了。原因是如果某個執行緒拿到公共資料477時,該執行緒就會申請一個gil lock,python直譯器就會呼叫系統的原生執行緒(我們常用的就是cPython,那麼呼叫的就是c的執行緒),python每執行100條指令(如:計算機底層對加這樣一個操作就需要幾百條的指令)就會釋放gil鎖,如果此時cpu還沒來得及在os平臺上做完運算就釋放了gil鎖,那麼477就會暫存在cpu的臨時快取中。另一個執行緒就會申請到gil鎖,此時,這個執行緒從公共資料中拿到的還是477,最後計算完後就是478,然後釋放gil鎖。剛剛還沒計算完的執行緒獲取到gil鎖後,接著從cpu暫存器(臨時快取)中取出477做完“加”運算返回給公共資料庫後還是478。這樣,出來的最後結果會少加1。所以,最好的辦法是加上一個執行緒鎖py3雖然沒有官方說明,但是貌似自己加上了執行緒鎖


這裡寫圖片描述
新增的執行緒鎖如下:

#-*- coding:utf-8 -*-
import threading
import time

lock = threading.Lock() #生成全域性鎖
def run():
    global num
    lock.acquire()  #修改資料前加鎖
    num += 1
    lock.release()  #修改資料後釋放鎖
    time.sleep(2)

num = 0
if __name__ == "__main__":
    for i in range(500):
        t1 = threading.Thread(target = run)
        t1.start()
    print(num)

====================================
從以下程式碼更能看出結果,如果加上鎖,輸出結果為執行緒1執行一段時間,然後執行緒2執行1段時間。如果不加上鎖,基本是3個執行緒輪流執行。

def sum(n):
    while True:
        global count
        # lock.acquire()
        count += 1
        print(n)
        # lock.release()

count = 0
lock = threading.Lock()

#lock = lock.acquire()   #如果還想在外面加上一層鎖,那麼lock = threading.RLock()  需要使用遞迴鎖
for i in range(3): t = threading.Thread(target=sum,args=(i,)) t.start() #lock = lock.release()

=====================
剛剛用執行緒寫一個生信的自動監測的指令碼的時候,就忽略了執行緒鎖,導致出現了這個問題,當t1執行緒進入了tumor_recal_split,這時,因為沒有加鎖,t1執行緒釋放了gil鎖,t2執行緒申請到gil鎖,然後t2執行緒進入normal_recal_split目錄。t2執行緒釋放gil鎖,t1執行緒申請到gil鎖,t1執行緒執行sh 1710260.recal.bat.sh發現沒有這個shell指令碼(因為當前是在normal_recal_split目錄下,只有1721010.recal.bat.sh指令碼)。如果給這2個函式加上執行緒鎖就ok了。
這裡寫圖片描述

這裡寫圖片描述