日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

聊聊 Python 中的同步原語,為什么有了 GIL 還需要同步原語

來源: 責編: 時間:2024-04-03 09:08:52 176觀看
導讀前言? 在前面的文章中我們介紹了 Python 中的全局解釋器鎖 GIL,我們知道 GIL 可以保證在多線程場景下同一時刻只有一個線程運行,但是并不能保證線程安全(所謂線程安全簡單來說就是程序在多線程環境中運行時,線程在交替運

前言

? 在前面的文章中我們介紹了 Python 中的全局解釋器鎖 GIL,我們知道 GIL 可以保證在多線程場景下同一時刻只有一個線程運行,但是并不能保證線程安全(所謂線程安全簡單來說就是程序在多線程環境中運行時,線程在交替運行時能正常的訪問共享資源,不會造成數據不一致或者死鎖,最后都能達到預期的結果),比如我們看下面的兩個例子:kRL28資訊網——每日最新資訊28at.com

對 counter 進行累加

import threadingimport timecounter = 0temp_count = 0def increment():    global counter, temp_count    for _ in range(1000):        counter += 1        temp = temp_count        time.sleep(0.0001)        temp_count = temp + 1start = time.time()threads = []for _ in range(10):    t = threading.Thread(target=increment)    threads.append(t)    t.start()for t in threads:    t.join()end = time.time()print("Final counter value:", counter)print("Final temp_count value:", temp_count)print(f"總共耗時:{end - start}")# 運行結果Final counter value: 10000Final temp_count value: 1001總共耗時:0.5465419292449951

? 上面我們對 counter 做多線程累積時,盡管 counter += 1 是非原子操作,但是由于 CPU 執行太快,因此我們很難復現線程不安全的情況,因此我們使用 temp_count 寫法進行手動模擬。kRL28資訊網——每日最新資訊28at.com

賬戶取款

import threadingclass BankAccount:    def __init__(self, balance):        self.balance = balance    def withdraw(self, amount):        if self.balance >= amount:            # 發生線程切換            self.balance -= amount            print(f"Withdrawal successful. Balance: {self.balance}")        else:            print("Insufficient funds")    def deposit(self, amount):        self.balance += amount        print(f"Deposit successful. Balance: {self.balance}")if __name__ == "__main__":    account = BankAccount(1000)    # 創建多個線程進行取款存款操作    threads = []    for _ in range(5):        t = threading.Thread(target=account.withdraw, args=(account, 200))        threads.append(t)        t.start()    for t in threads:        t.join()

? 上面的代碼同樣是線程不安全的,考慮這個場景,如果此時賬戶余額中剩余200,線程1執行完 self.balance >= amount 后切換到線程2,線程2正常取款200,然后切換回線程1,導致此時余額為-2200。kRL28資訊網——每日最新資訊28at.com

使用同步原語保證線程安全

? 從上面的兩個案例中我們可以看出,GIL 并不能保證線程安全,我們需要使用同步原語來進行線程同步保證線程安全。kRL28資訊網——每日最新資訊28at.com

locked、release 顯式獲取鎖和釋放鎖

? 在一些比較老的 python 代碼中,我們可以看到很多使用 locked、release 顯式獲取鎖和釋放鎖 的用法。kRL28資訊網——每日最新資訊28at.com

import threadingclass BankAccount:    def __init__(self, balance):        self.balance = balance        self.lock = threading.Lock()    def withdraw(self, amount):        self.lock.locked()        if self.balance >= amount:            self.balance -= amount            print(f"Withdrawal successful. Balance: {self.balance}")        else:            print("Insufficient funds")        self.lock.release()    def deposit(self, amount):        self.lock.locked()        self.balance += amount        print(f"Deposit successful. Balance: {self.balance}")        self.lock.release()if __name__ == "__main__":    account = BankAccount(1000)    # 創建多個線程進行取款存款操作    threads = []    for _ in range(5):        t = threading.Thread(target=account.withdraw, args=(account, 200))        threads.append(t)        t.start()    for t in threads:        t.join()

使用 with 語句同步原理

? 相比于這種顯式調用的方法,with 語句更加優雅,也更不容易出錯,特別是程序員可能會忘記調用 release() 方法或者程序在獲得鎖之后產生異常這兩種情況(使用 with 語句可以保證在這兩種情況下仍能正確釋放鎖)。kRL28資訊網——每日最新資訊28at.com

import threadingclass BankAccount:    def __init__(self, balance):        self.balance = balance        self.lock = threading.Lock()    def withdraw(self, amount):        with self.lock:            if self.balance >= amount:                self.balance -= amount                print(f"Withdrawal successful. Balance: {self.balance}")            else:                print("Insufficient funds")    def deposit(self, amount):        with self.lock:            self.balance += amount            print(f"Deposit successful. Balance: {self.balance}")if __name__ == "__main__":    account = BankAccount(1000)    # 創建多個線程進行取款存款操作    threads = []    for _ in range(5):        t = threading.Thread(target=account.withdraw, args=(account, 200))        threads.append(t)        t.start()    for t in threads:        t.join()

其它支持同步原語:RLock 和 Semaphore

RLock

? 一個 RLock (可重入鎖)可以被同一個線程多次獲取,主要用來實現基于監測對象模式的鎖定和同步。在使用這種鎖的情況下,當鎖被持有時,只有一個線程可以使用完整的函數或者類中的方法。kRL28資訊網——每日最新資訊28at.com

import threadingclass SharedCounter:    '''    A counter object that can be shared by multiple threads.    '''    _lock = threading.RLock()    def __init__(self, initial_value = 0):        self._value = initial_value    def incr(self,delta=1):        '''        Increment the counter with locking        '''        with SharedCounter._lock:            self._value += delta    def decr(self,delta=1):        '''        Decrement the counter with locking        '''        with SharedCounter._lock:             self.incr(-delta)

? 在上邊這個例子中,沒有對每一個實例中的可變對象加鎖,取而代之的是一個被所有實例共享的類級鎖。這個鎖用來同步類方法,具體來說就是,這個鎖可以保證一次只有一個線程可以調用這個類方法。不過,與一個標準的鎖不同的是,已經持有這個鎖的方法在調用同樣使用這個鎖的方法時,無需再次獲取鎖。比如 decr 方法。 這種實現方式的一個特點是,無論這個類有多少個實例都只用一個鎖。因此在需要大量使用計數器的情況下內存效率更高。不過這樣做也有缺點,就是在程序中使用大量線程并頻繁更新計數器時會有爭用鎖的問題。kRL28資訊網——每日最新資訊28at.com

Semaphore

? 信號量對象是一個建立在共享計數器基礎上的同步原語。如果計數器不為0,with 語句將計數器減1,線程被允許執行。with 語句執行結束后,計數器加1。如果計數器為0,線程將被阻塞,直到其他線程結束將計數器加1。kRL28資訊網——每日最新資訊28at.com

import urllib.requestfrom threading import Semaphore# At most, five threads allowed to run at once_fetch_url_sema = Semaphore(5)def fetch_url(url):    with _fetch_url_sema:        return urllib.request.urlopen(url)

本文鏈接:http://www.www897cc.com/showinfo-26-81056-0.html聊聊 Python 中的同步原語,為什么有了 GIL 還需要同步原語

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 我們一起聊聊軟件架構伸縮性法則

下一篇: React 19 要來了!究竟帶來了哪些實用的特性呢?

標簽:
  • 熱門焦點
  • 直屏旗艦來了 iQOO 12和K70 Pro同臺競技

    旗艦機基本上使用的都是雙曲面屏幕,這就讓很多喜歡直屏的愛好者在苦等一款直屏旗艦,這次,你們等到了。據博主數碼閑聊站帶來的最新爆料稱,Redmi下代旗艦K70 Pro和iQOO 12兩款手
  • JavaScript 混淆及反混淆代碼工具

    介紹在我們開始學習反混淆之前,我們首先要了解一下代碼混淆。如果不了解代碼是如何混淆的,我們可能無法成功對代碼進行反混淆,尤其是使用自定義混淆器對其進行混淆時。什么是混
  • 一年經驗在二線城市面試后端的經驗分享

    忠告這篇文章只適合2年內工作經驗、甚至沒有工作經驗的朋友閱讀。如果你是2年以上工作經驗,請果斷劃走,對你沒啥幫助~主人公這篇文章內容來自 「升職加薪」星球星友 的投稿,坐
  • 分布式系統中的CAP理論,面試必問,你理解了嘛?

    對于剛剛接觸分布式系統的小伙伴們來說,一提起分布式系統,就感覺高大上,深不可測。而且看了很多書和視頻還是一臉懵逼。這篇文章主要使用大白話的方式,帶你理解一下分布式系統
  • 得物效率前端微應用推進過程與思考

    一、背景效率工程隨著業務的發展,組織規模的擴大,越來越多的企業開始意識到協作效率對于企業團隊的重要性,甚至是決定其在某個行業競爭中突圍的關鍵,是企業長久生存的根本。得物
  • 讓我們一起聊聊文件的操作

    文件【1】文件是什么?文件是保存數據的地方,是數據源的一種,比如大家經常使用的word文檔、txt文件、excel文件、jpg文件...都是文件。文件最主要的作用就是保存數據,它既可以保
  • ESG的面子與里子

    來源 | 光子星球撰文 | 吳坤諺編輯 | 吳先之三伏大幕拉起,各地高溫預警不絕,但處于厄爾尼諾大“烤”之下的除了眾生,還有各大企業發布的ESG報告。ESG是“環境保
  • 與兆芯合作 聯想推出全新旗艦版筆記本電腦開天N7系列

    聯想與兆芯合作推出全新聯想旗艦版筆記本電腦開天 N7系列。這個系列采用兆芯KX-6640MA處理器平臺,KX-6640MA 處理器是采用了陸家嘴架構,16nm 工藝,4 核 4 線
  • 北京:科技教育體驗基地開始登記

      北京“科技館之城”科技教育體驗基地登記和認證工作日前啟動。首批北京科技教育體驗基地擬于2023年全國科普日期間掛牌,后續還將開展常態化登記?! ”本┛萍冀逃w驗基
Top 主站蜘蛛池模板: 古浪县| 江川县| 金坛市| 藁城市| 沿河| 丰镇市| 封开县| 秦安县| 双鸭山市| 宁波市| 碌曲县| 皮山县| 泾源县| 永靖县| 石嘴山市| 铁岭市| 陇川县| 罗山县| 藁城市| 伊金霍洛旗| 永川市| 蒙山县| 宁明县| 忻城县| 繁峙县| 陈巴尔虎旗| 尼玛县| 双流县| 湖北省| 临泉县| 西林县| 临猗县| 博客| 湄潭县| 海原县| 宁海县| 防城港市| 汾阳市| 农安县| 仙桃市| 舒城县|