欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Go語言擴展原語之Semaphore的用法詳解

 更新時間:2023年07月20日 15:52:50   作者:碼一行  
Go語言的擴展包中提供了帶權(quán)重的信號量?semaphore.Weighted,讓我們可以按照不同的權(quán)重管理資源的訪問,下面小編就來和大家聊聊它們的具體用法吧

概述

信號量是并發(fā)編程中常見的一種同步機制,在需要控制訪問資源的進程數(shù)量時就會用到信號量,它會保證持有的計數(shù)器在 0 到初始化的權(quán)重之間波動。

  • 每次獲取的資源都會將信號量中的計數(shù)器減去對應(yīng)的數(shù)值,在釋放時重新加回來
  • 當遇到計數(shù)器大于信號量大小時,會進入休眠等待其他線程釋放信號

Go語言的擴展包中提供了帶權(quán)重的信號量 semaphore.Weighted,我們可以按照不同的權(quán)重管理資源的訪問,這種結(jié)構(gòu)體暴露了 4 個方法:

  • semaphore.NewWeighted —— 用于創(chuàng)建新的信號量
  • semaphore.Weighted.Acquire —— 阻塞地獲取指定權(quán)重的資源,如果當前沒有空閑資源,會陷入休眠等待
  • semaphore.Weighted.TryAcquire —— 非阻塞地獲取指定權(quán)重的資源,如果當前沒有空閑資源,會直接返回 false
  • semaphore.Weighted.Relesae —— 用于釋放指定權(quán)重的資源

結(jié)構(gòu)體

semaphore.NewWeighted 方法能提供傳入的大量權(quán)重創(chuàng)建一個指向 semaphore.Weighted 結(jié)構(gòu)體的指針:

func NewWeighted(n int64) *Weighted {
    w := &Weighted{size: n}
    return w
}
type Weighted struct {
    size    int64
    cur     int64
    mu      sync.Mutex
    waiters list.list
}

semaphore.Weighted 結(jié)構(gòu)體中包含一個 waiters 列表,其中存儲著等待獲取資源的 Goroutine。除此之外,它還包含當前信號量的上限以及一個計數(shù)器 cur, 這個計數(shù)器的范圍就是 [0,size]

信號量中的計數(shù)器會隨著用戶對資源的訪問和釋放而改變,引入的權(quán)重概念能夠提供更細粒度的資源訪問控制,盡可能滿足常見用例。

獲取

semaphore.Weighted.Acquire 方法能用于獲取指定權(quán)重的資源,其中包含 3 中情況:

  • 當信號量中剩余資源大于獲取的資源并且沒有等待的 Goroutine 時,會直接獲取信號量
  • 當需要獲取的信號量大于 semaphore.Weighted 的上限時,由于不可能滿足條件,因此會直接返回錯誤
  • 遇到其他情況時,會將當前 Goroutine 加入等待列表,并通過 select 等待調(diào)度器喚醒當前 Goroutine,Goroutine 被喚醒后會獲取信號量
func (s *Weighted) Acquire(ctx context.Context, n int64) error {
    if s.size - s.cur >= n && len(s.waiters) == 0 {
        s.cur += n
        return nil
    }
    ...
    ready := make(chan struct{})
    w := waiter{n: n, ready: ready}
    elem := s.waiters.PushBack(w)
    select {
    case <-ctx.Done():
        err := ctx.Err()
        select {
        case <-ready:
            err = nil
        default:
            s.waiters.Remove(elem)
        }
        return err
    case <-ready:
        return nil
    }
}

另一個用于獲取信號量的方法 semaphore.Weighted.TryAcquire 只會非阻塞地判斷當前信號量是否有充足的資源,如果有,會立刻返回 true, 否則會返回 false :

func (s *Weighted) TryAcquire(n int64) bool {
    s.mu.Lock()
    success := s.size-s.cur >= n && len(s.waiters) == 0
    if success {
        s.cur += n
    }
    s.mu.Unlock()
    return success
}

因為 semaphore.Weighted.TryAcquire 不會等待資源的釋放,所以可能更適用于一些對延時敏感、用戶需要立刻感知結(jié)果的場景

釋放

當我們要釋放信號量時,semaphore.Weighted.Relesae 方法會從頭到尾遍歷 waiters 列表中全部的等待者,如果釋放資源后的信號量有充足的剩余資源,就會通過 Channel 喚醒指定的 Goroutine:

func (c *Weighted) Relesae(n int64) {
    s.mu.Lock()
    s.cur -= n
    for {
        next := w.waiters.Front()
        if next == nil {
            break
        }
        w := next.Value.(waiter)
        if s.size-s.cur < w.n {
            break
        }
        s.cur += w.n
        s.waiters.Remove(next)
        close(w.ready)
    }
    s.mu.Unlock()
}

當然,也可能會出現(xiàn)剩余資源無法喚醒 Channel 的情況,這時當前方法釋放鎖之后會直接返回。

通過 semaphore.Weighted.Relesae 的分析我們可以發(fā)現(xiàn),如果一個信號量需要占用的資源非常多,它可能會長時間無法獲取鎖,這也是 semaphore.Weighted.Acquire 引入上下文參數(shù)的原因,即為信號量的獲取設(shè)置超時時間。

小結(jié)

帶權(quán)重的信號量確實有更多的應(yīng)用場景,,這也是Go語言對外提供的唯一信號量實現(xiàn),使用過程中需要注意以下幾個問題:

  • semaphore.Weighted.Acquire 和 semaphore.Weighted.TryAcquire 都可以適用于獲取資源,前者會阻塞獲取信號量,后者會非阻塞獲取信號量
  • semaphore.Weighted.Relesae 方法會按照先進先出的順序喚醒可以被喚醒的 Goroutine
  • 如果一個 Goroutine 獲取了較多的資源,由于 semaphore.Weighted.Relesae 的釋放策略可能會等待較長時間

到此這篇關(guān)于Go語言擴展原語之Semaphore的用法詳解的文章就介紹到這了,更多相關(guān)Go語言Semaphore內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言調(diào)用DeepSeek?API實現(xiàn)流式輸出和對話

    Go語言調(diào)用DeepSeek?API實現(xiàn)流式輸出和對話

    DeepSeek是一個強大的AI模型服務(wù)平臺,本文將詳細介紹如何使用Go語言調(diào)用DeepSeek?API實現(xiàn)流式輸出和對話功能,感興趣的小伙伴可以了解一下
    2025-02-02
  • go語言開發(fā)中如何優(yōu)雅得關(guān)閉協(xié)程方法

    go語言開發(fā)中如何優(yōu)雅得關(guān)閉協(xié)程方法

    這篇文章主要為大家介紹了go語言開發(fā)中如何優(yōu)雅得關(guān)閉協(xié)程方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • Go語言學(xué)習(xí)函數(shù)+結(jié)構(gòu)體+方法+接口

    Go語言學(xué)習(xí)函數(shù)+結(jié)構(gòu)體+方法+接口

    這篇文章主要介紹了Go語言學(xué)習(xí)函數(shù)+結(jié)構(gòu)體+方法+接口,文章圍繞主題的相關(guān)資料展開詳細的文章說明,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-05-05
  • Golang的鎖機制與使用技巧小結(jié)

    Golang的鎖機制與使用技巧小結(jié)

    本文主要介紹了Golang的鎖機制與使用技巧小結(jié),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Go讀取配置文件的方法總結(jié)

    Go讀取配置文件的方法總結(jié)

    我們常見的配置文件的格式一般有:XML、JSON、INI、YAML、env和.properties,本文小編為大家整理了Go語言讀取這些格式的配置文件的方法,希望對大家有所幫助
    2023-10-10
  • golang 生成對應(yīng)的數(shù)據(jù)表struct定義操作

    golang 生成對應(yīng)的數(shù)據(jù)表struct定義操作

    這篇文章主要介紹了golang 生成對應(yīng)的數(shù)據(jù)表struct定義操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 從零封裝Gin框架配置初始化全局變量

    從零封裝Gin框架配置初始化全局變量

    這篇文章主要為大家介紹了從零封裝Gin框架配置初始化全局變量,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-01-01
  • 一文帶你了解Golang中的泛型

    一文帶你了解Golang中的泛型

    泛型是一種可以編寫?yīng)毩⒂谑褂玫奶囟愋偷拇a的方法,可以通過編寫函數(shù)或類型來使用一組類型中的任何一個,下面就來和大家聊聊Golang中泛型的使用吧
    2023-07-07
  • Go Gin框架中的binding驗證器使用小結(jié)

    Go Gin框架中的binding驗證器使用小結(jié)

    Gin框架中的binding驗證器為我們提供了簡便的數(shù)據(jù)綁定和驗證功能,通過合理使用binding和validate標簽,我們可以確保API接口的數(shù)據(jù)合法性和完整性,這篇文章主要介紹了Go Gin框架中的binding驗證器使用指南,需要的朋友可以參考下
    2024-07-07
  • go?proto編譯引用外部包問題解決方案示例

    go?proto編譯引用外部包問題解決方案示例

    這篇文章主要為大家介紹了go?proto編譯引用外部包問題解決方案示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10

最新評論