成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

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

開發(fā) 前端
一個 RLock (可重入鎖)可以被同一個線程多次獲取,主要用來實現(xiàn)基于監(jiān)測對象模式的鎖定和同步。在使用這種鎖的情況下,當鎖被持有時,只有一個線程可以使用完整的函數(shù)或者類中的方法。

前言

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

對 counter 進行累加

import threading
import time

counter = 0
temp_count = 0


def increment():
    global counter, temp_count
    for _ in range(1000):
        counter += 1
        temp = temp_count
        time.sleep(0.0001)
        temp_count = temp + 1


start = 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}")

# 運行結(jié)果
Final counter value: 10000
Final temp_count value: 1001
總共耗時:0.5465419292449951

? 上面我們對 counter 做多線程累積時,盡管 counter += 1 是非原子操作,但是由于 CPU 執(zhí)行太快,因此我們很難復現(xiàn)線程不安全的情況,因此我們使用 temp_count 寫法進行手動模擬。

賬戶取款

import threading


class BankAccount:
    def __init__(self, balance):
        self.balance = balance

    def withdraw(self, amount):
        if self.balance >= amount:
            # 發(fā)生線程切換
            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)

    # 創(chuàng)建多個線程進行取款存款操作
    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執(zhí)行完 self.balance >= amount 后切換到線程2,線程2正常取款200,然后切換回線程1,導致此時余額為-2200。

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

? 從上面的兩個案例中我們可以看出,GIL 并不能保證線程安全,我們需要使用同步原語來進行線程同步保證線程安全。

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

? 在一些比較老的 python 代碼中,我們可以看到很多使用 locked、release 顯式獲取鎖和釋放鎖 的用法。

import threading


class 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)

    # 創(chuàng)建多個線程進行取款存款操作
    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 語句同步原理

? 相比于這種顯式調(diào)用的方法,with 語句更加優(yōu)雅,也更不容易出錯,特別是程序員可能會忘記調(diào)用 release() 方法或者程序在獲得鎖之后產(chǎn)生異常這兩種情況(使用 with 語句可以保證在這兩種情況下仍能正確釋放鎖)。

import threading


class 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)

    # 創(chuàng)建多個線程進行取款存款操作
    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 (可重入鎖)可以被同一個線程多次獲取,主要用來實現(xiàn)基于監(jiān)測對象模式的鎖定和同步。在使用這種鎖的情況下,當鎖被持有時,只有一個線程可以使用完整的函數(shù)或者類中的方法。

import threading

class 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)

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

Semaphore

? 信號量對象是一個建立在共享計數(shù)器基礎上的同步原語。如果計數(shù)器不為0,with 語句將計數(shù)器減1,線程被允許執(zhí)行。with 語句執(zhí)行結(jié)束后,計數(shù)器加1。如果計數(shù)器為0,線程將被阻塞,直到其他線程結(jié)束將計數(shù)器加1。

import urllib.request
from 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)
責任編輯:武曉燕 來源: Lorin 洛林
相關推薦

2023-09-12 14:02:30

數(shù)組vector

2023-10-24 15:15:26

HTTPWebSocket

2021-10-12 18:48:07

HTTP 協(xié)議Websocket網(wǎng)絡通信

2020-10-12 06:52:56

無線通信基站

2024-02-22 10:34:00

NULLC++nullptr

2024-02-18 12:39:15

C++autodecltype

2023-12-25 09:58:25

sync包Go編程

2024-10-31 11:32:28

2024-11-26 07:37:22

2016-01-28 10:04:09

Jenkins運維持續(xù)交付

2025-04-09 11:15:00

服務熔斷服務降分布式系統(tǒng)

2020-05-13 15:57:59

聚類分析算法監(jiān)督學習

2025-01-07 14:36:12

2023-01-31 17:24:21

DPUCPUGPU

2023-09-14 16:02:27

2023-04-07 15:30:24

操作系統(tǒng)ChatGPT

2023-06-01 07:50:42

JSDocTypeScriptAPI

2015-06-19 06:41:45

生命科學云計算集群計算

2020-12-11 07:39:37

RPC MQ架構(gòu)

2020-12-15 06:57:24

java服務器
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 美女爽到呻吟久久久久 | 国产乱码精品一品二品 | 日韩精品免费一区二区在线观看 | 中文字幕 国产 | 国产精品精品3d动漫 | 午夜影院网站 | 最新国产精品视频 | 午夜激情网 | 成人一区二区三区 | 亚洲免费视频网站 | 国产日韩精品在线 | 九九九久久国产免费 | 国产精品美女一区二区 | 男人的天堂avav | 欧美日韩亚洲国产综合 | 在线观看中文字幕dvd播放 | 成人午夜精品一区二区三区 | 99在线免费观看视频 | 国产精品久久九九 | 久久久91精品国产一区二区三区 | 一区二区在线 | 国产亚洲成av人在线观看导航 | 欧美精品久久久 | 天天操天天舔 | 日本高清中文字幕 | 亚洲成av人片在线观看无码 | 国产中文字幕亚洲 | 亚洲视频www| 在线视频成人 | 欧美aⅴ| 亚洲国产高清高潮精品美女 | 国产小视频在线观看 | 亚洲一区二区中文字幕 | 成人精品视频在线 | 91精品国产综合久久福利软件 | 99热首页 | 精品婷婷| 国产精品久久久久久 | 成人小视频在线免费观看 | 一区二区三区视频 | 日日噜|