python3 線程與線程之間數據是共享的(鎖和死鎖)


線程與線程之間數據是共享的

from threading import Thread


def func(lst, name):
    lst.append(66)
    print(name, lst)


if __name__ == '__main__':
    lst = [1, 2]
    t1 = Thread(target=func, args=(lst, "線程1"))
    t2 = Thread(target=func, args=(lst, "線程2"))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print("主線程結束", lst)

執行結果:

線程1 [1, 2, 66]
線程2 [1, 2, 66, 66]
主線程結束 [1, 2, 66, 66]

 

帶有global的線程與線程之間的數據共享情況

from threading import Thread


def func(name):
    global n
    print(f"{name}開始,n={n}")
    n = 0
    print(f"{name}結束,n={n}")


if __name__ == '__main__':
    n = 100
    t1 = Thread(target=func, args=("線程1",))
    t1.start()
    t1.join()
    print(f"主線程結束,n={n}")

執行結果:

線程1開始,n=100
線程1結束,n=0
主線程結束,n=0

 

接下來看一個由於線程之間的數據是共享而引發問題

from threading import Thread


def func(name):
    print(f"{name}開始")
    global n
    for i in range(100000):
        n += 1
    print(f"{name}結束,n={n}")


if __name__ == '__main__':
    n = 0
    t1 = Thread(target=func, args=("線程1",))
    t2 = Thread(target=func, args=("線程2",))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(f"主線程結束,n={n}")

執行結果:

線程1開始
線程2開始
線程1結束,n=165337
線程2結束,n=147914
主線程結束,n=147914

最終的結果不是我們預期的200000

 

解決線程與線程之間數據共享導致的問題:加鎖

from threading import Thread, Lock


def func(name, lock: Lock):  # 傳遞lock,后面添加: Lock表示是Lock類型的是為了上鎖和釋放鎖的時候會有方法提示功能
    print(f"{name}開始")
    global n
    for i in range(100000):
        lock.acquire()  # 上鎖
        n += 1
        lock.release()  # 釋放鎖
    print(f"{name}結束,n={n}")


if __name__ == '__main__':
    lock = Lock()  # 創建一把鎖
    n = 0
    t1 = Thread(target=func, args=("線程1", lock))
    t2 = Thread(target=func, args=("線程2", lock))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(f"主線程結束,n={n}")

執行結果:

線程1開始
線程2開始
線程1結束,n=167229
線程2結束,n=200000
主線程結束,n=200000

只看最終結果就行,因為線程1和線程2是並行執行的。

 

線程與線程之間數據共享(加鎖)

from threading import Thread, Lock


n = 0
def func(lock, name):
    lock.acquire()
    global n
    for i in range(1000000):
        n += 1
    print("%s拿到了鎖" % name)
    lock.release()


if __name__ == '__main__':
    lock = Lock()  # 線程鎖
    t1 = Thread(target=func, args=(lock, "線程1"))
    t2 = Thread(target=func, args=(lock, "線程2"))
    t3 = Thread(target=func, args=(lock, "線程3"))
    t1.start()
    t2.start()
    t3.start()
    t1.join()
    t2.join()
    t3.join()
    print(n)

運行結果:

線程1拿到了鎖
線程2拿到了鎖
線程3拿到了鎖
3000000

 

死鎖現象

from threading import Thread, Lock


def func(name, lock: Lock):  # 傳遞lock,后面添加: Lock表示是Lock類型的,是為了上鎖和釋放鎖的時候會有方法提示功能
    print(f"{name}開始")
    lock.acquire()  # 上鎖
    lock.acquire()  # 上鎖
    print(f"{name}被鎖住了")
    lock.release()  # 釋放鎖
    lock.release()  # 釋放鎖
    print(f"{name}結束")


if __name__ == '__main__':
    lock = Lock()  # 創建一把鎖
    t1 = Thread(target=func, args=("線程1", lock))
    t2 = Thread(target=func, args=("線程2", lock))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(f"主線程結束")

執行結果:

線程1開始
線程2開始

程序一直執行不完,因為程序被鎖住了。

 

解決死鎖--->使用遞歸鎖RLock

from threading import Thread, RLock


def func(name, lock: RLock):  # 傳遞lock,后面添加: Lock表示是Lock類型的,是為了上鎖和釋放鎖的時候會有方法提示功能
    print(f"{name}開始")
    lock.acquire()  # 上鎖
    lock.acquire()  # 上鎖
    print(f"{name}被鎖住了")
    lock.release()  # 釋放鎖
    lock.release()  # 釋放鎖
    print(f"{name}結束")


if __name__ == '__main__':
    lock = RLock()  # 創建一把鎖
    t1 = Thread(target=func, args=("線程1", lock))
    t2 = Thread(target=func, args=("線程2", lock))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(f"主線程結束")

執行結果:

線程1開始
線程1被鎖住了
線程1結束
線程2開始
線程2被鎖住了
線程2結束
主線程結束

完美解決死鎖的問題,切記鎖可以保證數據的安全性,但是效率會降低,相當於把並行改為了串行。

死鎖可以想成兩個人圍着桌子吃飯,兩個人的中間各放着一根的筷子,兩根筷子在一起才能吃飯,此時,兩個人都想吃飯,但是都抓着筷子不放開,結果誰也吃不上飯,就僵死在那了。


免責聲明!

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



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