亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

第十五章、Python多線程同步鎖,死鎖和遞歸鎖

系統 1740 0

目錄

  • 第十五章、Python多線程同步鎖,死鎖和遞歸鎖
    • 1. 引子:
    • 2.同步鎖
    • 3.死鎖
      • 引子:
    • 4.遞歸鎖RLock
      • 原理:
      • 不多說,放代碼
      • 總結:
    • 5. 大總結

第十五章、Python多線程同步鎖,死鎖和遞歸鎖

1. 引子:

          
            1.創建線程對象
t1 = threading.Thread(target=say,args=('tony',))
2.啟動線程
t1.start()
后面又說了兩個點就是join和守護線程的概念
          
        

? 以上就是python多線程的基本使用

? 說明:前面說的兩個功能是相互獨立的,相互不干涉的,不會用到同享的資源或者數據,如果我們多個線程要用到相同的數據,那么就會存在資源爭用和鎖的問題,不管在什么語言中,這個都是不能避免的。 那么接下來講講同步鎖,死鎖和遞歸鎖的使用

2.同步鎖

? 鎖通常被用來實現對共享資源的同步訪問。為每一個共享資源創建一個Lock對象,當你需要訪問該資源時,調用acquire方法來獲取鎖對象(如果其它線程已經獲得了該鎖,則當前線程需等待其被釋放),待資源訪問完后,再調用release方法釋放鎖。

? 適用同步鎖的例子如下:

          
            import threading
import time

num = 100

def fun_sub():
    global num
    # num -= 1
    num2 = num
    time.sleep(0.001)
    num = num2-1

if __name__ == '__main__':
    print('開始測試同步鎖 at %s' % time.ctime())

    thread_list = []
    for thread in range(100):
        t = threading.Thread(target=fun_sub)
        t.start()
        thread_list.append(t)

    for t in thread_list:
        t.join()
    print('num is %d' % num)
    print('結束測試同步鎖 at %s' % time.ctime())
-----------------------------------------------------
開始測試同步鎖 at Sun Apr 28 09:56:45 2019
num is 91
結束測試同步鎖 at Sun Apr 28 09:56:45 2019
          
        

這樣的例子描述 :創建100的線程,然后每個線程去從公共資源num變量去執行減1操作,按照正常情況下面,等到代碼執行結束,打印num變量,應該得到的是0,因為100個線程都去執行了一次減1的操作。

這樣的問題是 :發現結果不是0而是91

讓我們整理一下代碼思路

1.因為GIL,只有一個線程(假設線程1)拿到了num這個資源,然后把變量賦值給num2,sleep 0.001秒,這時候num=100
2.當第一個線程sleep 0.001秒這個期間,這個線程會做yield操作,就是把cpu切換給別的線程執行(假設線程2拿到個GIL,獲得cpu使用權),線程2也和線程1一樣也拿到num,返回賦值給num2,然后sleep,這時候,其實num還是=100.
3.線程2 sleep時候,又要yield操作,假設線程3拿到num,執行上面的操作,其實num有可能還是100
4.等到后面cpu重新切換給線程1,線程2,線程3上執行的時候,他們執行減1操作后,其實等到的num其實都是99,而不是順序遞減的。
5.其他剩余的線程操作如上

解決方案 :這里就要借助于python的同步鎖了,也就是同一時間只能放一個線程來操作num變量,減1之后,后面的線程操作來操作num變量。看看下面我們怎么實現。

          
            import threading
import time

num = 100

def fun_sub():
    global num
    lock.acquire()
    print('----加鎖----')
    print('現在操作共享資源的線程名字是:',t.name)
    num2 = num
    time.sleep(0.001)
    num = num2-1
    lock.release()
    print('----釋放鎖----')

if __name__ == '__main__':
    print('開始測試同步鎖 at %s' % time.ctime())

    lock = threading.Lock() #創建一把同步鎖

    thread_list = []
    for thread in range(100):
        t = threading.Thread(target=fun_sub)
        t.start()
        thread_list.append(t)

    for t in thread_list:
        t.join()
    print('num is %d' % num)
    print('結束測試同步鎖 at %s' % time.ctime())
 ------------------------------------------------
 .......
----加鎖----
現在操作共享資源的線程名字是: Thread-98
----釋放鎖----
----加鎖----
現在操作共享資源的線程名字是: Thread-100
----釋放鎖----
num is 0
結束測試同步鎖 at Sun Apr 28 12:08:27 2019
          
        

思路 :看到上面我們給中間的減1代碼塊,加個一把同步鎖,這樣,我們就可以得到我們想要的結果了,這就是同步鎖的作用,一次只有一個線程操作同享資源。

3.死鎖

引子:

? 死鎖的這個概念在很多地方都存在,比較在數據中,大概介紹下死鎖是怎么產生的

          
            # 線程1拿到了(鎖頭2)想要往下執行需要(鎖頭1),
# 線程2拿到了(鎖頭1)想要往下執行需要(鎖頭2)
# 互相都拿到了彼此想要往下執行的必需條件,互相都不放手里的鎖頭.
# 產生了死鎖問題
          
        

產生原因: python中在線程間共享多個資源的時候,如果兩個線程分別占有一部分資源并且同時等待對方的資源,就會造成死鎖,因為系統判斷這部分資源都正在使用,所有這兩個線程在無外力作用下將一直等待下去。

          
            from threading import Thread,Lock
mutex1 = Lock()
mutex2 = Lock()
import time
class MyThreada(Thread):
    def run(self):
        self.task1()
        self.task2()
    def task1(self):
        mutex1.acquire()
        print(f'{self.name} 搶到了 鎖1 ')
        mutex2.acquire()
        print(f'{self.name} 搶到了 鎖2 ')
        mutex2.release()
        print(f'{self.name} 釋放了 鎖2 ')
        mutex1.release()
        print(f'{self.name} 釋放了 鎖1 ')

    def task2(self):
        mutex2.acquire()
        print(f'{self.name} 搶到了 鎖2 ')
        time.sleep(1)
        mutex1.acquire()
        print(f'{self.name} 搶到了 鎖1 ')
        mutex1.release()
        print(f'{self.name} 釋放了 鎖1 ')
        mutex2.release()
        print(f'{self.name} 釋放了 鎖2 ')

for i in range(3):
    t = MyThreada()
    t.start()
          
        

那么,為了解決這個死鎖問題,就引入了遞歸鎖方案

4.遞歸鎖RLock

原理:

? 為了支持在同一線程中多次請求同一資源,python提供了"遞歸鎖":threading.RLock。RLock內部維護著一個Lock和一個counter變量,counter記錄了acquire的次數,從而使得資源可以被多次acquire。直到一個線程所有的acquire都被release,其他的線程才能獲得資源

不多說,放代碼

          
            from threading import Thread,Lock,RLock
# mutex1 = Lock()
# mutex2 = Lock()
mutex1 = RLock()
mutex2 = mutex1

import time
class MyThreada(Thread):
    def run(self):
        self.task1()
        self.task2()
    def task1(self):
        mutex1.acquire()
        print(f'{self.name} 搶到了 鎖1 ')
        mutex2.acquire()
        print(f'{self.name} 搶到了 鎖2 ')
        mutex2.release()
        print(f'{self.name} 釋放了 鎖2 ')
        mutex1.release()
        print(f'{self.name} 釋放了 鎖1 ')

    def task2(self):
        mutex2.acquire()
        print(f'{self.name} 搶到了 鎖2 ')
        time.sleep(1)
        mutex1.acquire()
        print(f'{self.name} 搶到了 鎖1 ')
        mutex1.release()
        print(f'{self.name} 釋放了 鎖1 ')
        mutex2.release()
        print(f'{self.name} 釋放了 鎖2 ')


for i in range(3):
    t = MyThreada()
    t.start()
          
        

總結:

? 上面我們用一把遞歸鎖,就解決了多個同步鎖導致的死鎖問題。大家可以把RLock理解為大鎖中還有小鎖,只有等到內部所有的小鎖,都沒有了,其他的線程才能進入這個公共資源。

5. 大總結

? 還有一點,并不是所有的多線程都存在數據不同步、死鎖的問題,但在訪問共享資源的時候,鎖是一定要存在了, 所以我們在代碼里面加鎖的時候,要注意在什么地方加,對性能的影響最小,這個就靠對邏輯的理解了。


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 四虎国产精品永久在线网址 | 国产精品原创永久在线观看 | 4huh34四虎最新久 | 香蕉视频成人在线观看 | 香蕉国产人午夜视频在线观看 | 日韩在线观看视频网站 | 伊人一伊人色综合网 | 久久思re热9一区二区三区 | 九热爱视频精品视频 | 中文字幕亚洲日韩无线码 | 亚洲视频一二区 | 天天插天天操 | 99re这里只有精品66 | 伊人久久99 | 京野结衣免费一区二区 | 国产在线观看美女福利精 | 国产福利久久 | 中文一区 | 立即播放免费毛片一级 | 国产一区二区三区在线影院 | 91日韩精品天海翼在线观看 | 欧美一级性视频 | 99热热热 | 97在线观免费视频观看 | 欧美一区二区三区免费观看视频 | 香香在线观看视频 | 欧美激情在线精品一区二区 | 久久精品视频5 | 婷婷在线视频观看 | 久久精品免费观看久久 | 色综合久久天天综合观看 | 欧美3区| 91精品成人福利在线播放 | 久青草视频在线播放 | 色妞色综合久久夜夜 | 97视频| 免费国产之a视频 | 亚洲欧美激情精品一区二区 | 狠狠的搞| 午夜精品久久久久久久第一页 | 亚洲精品一区亚洲精品 |