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

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

Go 語言中 sync 包的近距離觀察

來源: 責編: 時間:2023-11-28 09:34:53 224觀看
導讀讓我們來看看負責提供同步原語的 Go 包:sync。sync.Mutexsync.Mutex 可能是 sync 包中被廣泛使用的原語。它允許對共享資源進行互斥操作(即不允許同時訪問):mutex := &sync.Mutex{}mutex.Lock()// Update shared variable

MVa28資訊網——每日最新資訊28at.com

讓我們來看看負責提供同步原語的 Go 包:sync。MVa28資訊網——每日最新資訊28at.com

sync.Mutex

sync.Mutex 可能是 sync 包中被廣泛使用的原語。它允許對共享資源進行互斥操作(即不允許同時訪問):MVa28資訊網——每日最新資訊28at.com

mutex := &sync.Mutex{}mutex.Lock()// Update shared variable (e.g. slice, pointer on a structure, etc.)mutex.Unlock()

必須指出的是 sync.Mutex 無法被復制(就像 sync 包中的所有其他原語一樣)。如果一個結構體有一個 sync 字段,必須通過指針進行傳遞。MVa28資訊網——每日最新資訊28at.com

sync.RWMutex

sync.RWMutex 是一個讀寫鎖。它提供了與我們剛剛看到的 Lock() 和 Unlock() 相同的方法(因為這兩個結構都實現了 sync.Locker 接口)。然而,它還允許使用 RLock() 和 RUnlock() 方法進行并發讀取:MVa28資訊網——每日最新資訊28at.com

mutex := &sync.RWMutex{}mutex.Lock()// Update shared variablemutex.Unlock()mutex.RLock()// Read shared variablemutex.RUnlock()

一個 sync.RWMutex 允許至少一個讀取者或正好一個寫入者,而一個 sync.Mutex 則允許正好一個讀取者或寫入者。MVa28資訊網——每日最新資訊28at.com

讓我們運行一個快速的基準測試來比較這些方法:MVa28資訊網——每日最新資訊28at.com

func BenchmarkMutexLock(b *testing.B) {    m := sync.Mutex{}    for i := 0; i < b.N; i++ {        m.Lock()        m.Unlock()    }}func BenchmarkRWMutexLock(b *testing.B) {    m := sync.RWMutex{}    for i := 0; i < b.N; i++ {        m.Lock()        m.Unlock()    }}func BenchmarkRWMutexRLock(b *testing.B) {    m := sync.RWMutex{}    for i := 0; i < b.N; i++ {        m.RLock()        m.RUnlock()    }}
BenchmarkMutexLock-4       83497579         17.7 ns/opBenchmarkRWMutexLock-4     35286374         44.3 ns/opBenchmarkRWMutexRLock-4    89403342         15.3 ns/op

正如我們注意到的那樣,讀取鎖定/解鎖 sync.RWMutex 比鎖定/解鎖 sync.Mutex 更快。另一方面,調用 Lock()/Unlock() 在 sync.RWMutex 上是最慢的操作。MVa28資訊網——每日最新資訊28at.com

總的來說,當我們有頻繁的讀取和不經常的寫入時,應該使用 sync.RWMutex。MVa28資訊網——每日最新資訊28at.com

sync.WaitGroup

sync.WaitGroup 也經常被使用。它是一個 goroutine 等待一組 goroutine 完成的慣用方式。MVa28資訊網——每日最新資訊28at.com

sync.WaitGroup 擁有一個內部計數器。如果這個計數器等于 0,Wait() 方法會立即返回。否則,它會被阻塞,直到計數器變為 0。MVa28資訊網——每日最新資訊28at.com

要增加計數器,我們可以使用 Add(int) 方法。要減少計數器,可以使用 Done()(將計數器減 1)或者使用帶有負值的相同的 Add(int) 方法。MVa28資訊網——每日最新資訊28at.com

在以下示例中,我們將啟動八個 goroutine 并等待它們完成:MVa28資訊網——每日最新資訊28at.com

wg := &sync.WaitGroup{}for i := 0; i < 8; i++ {  wg.Add(1)  go func() {    // Do something    wg.Done()  }()}wg.Wait()// Continue execution

每次我們創建一個 goroutine 時,都會使用 wg.Add(1) 來增加 wg 的內部計數器。我們也可以在 for 循環外部調用 wg.Add(8)。MVa28資訊網——每日最新資訊28at.com

與此同時,每當一個 goroutine 完成時,它會使用 wg.Done() 來減少 wg 的內部計數器。MVa28資訊網——每日最新資訊28at.com

一旦執行了八個 wg.Done() 語句,主 goroutine 就會繼續執行。MVa28資訊網——每日最新資訊28at.com

sync.Map

sync.Map 是 Go 中的一個并發版本的 map,我們可以:MVa28資訊網——每日最新資訊28at.com

  • 使用 Store(interface{}, interface{}) 添加元素
  • 使用 Load(interface) interface{} 檢索元素
  • 使用 Delete(interface{}) 刪除元素
  • 使用 LoadOrStore(interface{}, interface{}) (interface, bool) 檢索或添加元素(如果之前不存在)。返回的 bool 值為 true 表示在操作前鍵存在于 map 中。
  • 使用 Range 在元素上進行迭代
m := &sync.Map{}// Put elementsm.Store(1, "one")m.Store(2, "two")// Get element 1value, contains := m.Load(1)if contains {  fmt.Printf("%s/n", value.(string))}// Returns the existing value if present, otherwise stores itvalue, loaded := m.LoadOrStore(3, "three")if !loaded {  fmt.Printf("%s/n", value.(string))}// Delete element 3m.Delete(3)// Iterate over all the elementsm.Range(func(key, value interface{}) bool {  fmt.Printf("%d: %s/n", key.(int), value.(string))  return true})

Go 在線測試: https://play.golang.org/p/BO8IDVIDwsrMVa28資訊網——每日最新資訊28at.com

onethree1: one2: two

正如你所看到的,Range 方法接受一個 func(key, value interface{}) bool 函數作為參數。如果我們返回 false,則迭代會停止。有趣的是,即使我們在恒定時間之后返回 false(更多信息),最壞情況下的時間復雜度仍然保持為 O(n)。MVa28資訊網——每日最新資訊28at.com

何時應該使用 sync.Map 而不是在經典的 map 上加 sync.Mutex 呢?MVa28資訊網——每日最新資訊28at.com

  • 當我們有頻繁讀取和不經常寫入時(與 sync.RWMutex 類似)
  • 當多個 goroutine 為不相交的鍵集合讀取、寫入和覆蓋條目。這具體意味著什么?例如,如果我們有一個分片實現,有 4 個 goroutine 每個負責 25% 的鍵(沒有沖突)。在這種情況下,sync.Map 也是首選。

sync.Pool

sync.Pool 是一個并發池,負責安全地保存一組對象。MVa28資訊網——每日最新資訊28at.com

其公共方法包括:MVa28資訊網——每日最新資訊28at.com

  • Get() interface{} 用于檢索一個元素
  • Put(interface{}) 用于添加一個元素
pool := &sync.Pool{}pool.Put(NewConnection(1))pool.Put(NewConnection(2))pool.Put(NewConnection(3))connection := pool.Get().(*Connection)fmt.Printf("%d/n", connection.id)connection = pool.Get().(*Connection)fmt.Printf("%d/n", connection.id)connection = pool.Get().(*Connection)fmt.Printf("%d/n", connection.id)
132

值得注意的是,就順序而言是沒有保證的。Get 方法指定它從池中獲取一個任意的項目。MVa28資訊網——每日最新資訊28at.com

也可以指定一個創建方法:MVa28資訊網——每日最新資訊28at.com

pool := &sync.Pool{  New: func() interface{} {    return NewConnection()  },}connection := pool.Get().(*Connection)

每次調用 Get() 時,它將返回由傳遞給 pool.New 的函數創建的對象(在本例中是一個指針)。MVa28資訊網——每日最新資訊28at.com

何時應該使用 sync.Pool 呢?有兩種情況:MVa28資訊網——每日最新資訊28at.com

  • 第一種情況是當我們需要重用共享且長期存在的對象時,比如一個數據庫連接。
  • 第二種情況是優化內存分配。

讓我們考慮一個函數的示例,該函數將數據寫入緩沖區并將結果持久化到文件中。使用 sync.Pool,我們可以重復使用分配給緩沖區的空間,跨不同的函數調用重復使用同一個對象。MVa28資訊網——每日最新資訊28at.com

第一步是檢索先前分配的緩沖區(或者如果是第一次調用,則創建一個,但這已經被抽象化了)。然后,延遲操作是將緩沖區放回池中。MVa28資訊網——每日最新資訊28at.com

func writeFile(pool *sync.Pool, filename string) error {    // Gets a buffer object    buf := pool.Get().(*bytes.Buffer)    // Returns the buffer into the pool    defer pool.Put(buf)    // Reset buffer otherwise it will contain "foo" during the first call    // Then "foofoo" etc.    buf.Reset()    buf.WriteString("foo")    return ioutil.WriteFile(filename, buf.Bytes(), 0644)}

sync.Pool 還有一個要提到的重要點。由于指針可以被放入 Get() 返回的接口值中,無需進行任何分配,因此最好將指針放入池中而不是結構體。MVa28資訊網——每日最新資訊28at.com

這樣,我們既可以有效地重用已分配的內存,又可以減輕垃圾收集器的壓力,因為如果變量逃逸到堆上,它就不需要再次分配內存。MVa28資訊網——每日最新資訊28at.com

sync.Once

sync.Once 是一個簡單而強大的原語,用于確保一個函數只被執行一次。MVa28資訊網——每日最新資訊28at.com

在這個例子中,將只有一個 goroutine 顯示輸出消息:MVa28資訊網——每日最新資訊28at.com

once := &sync.Once{}for i := 0; i < 4; i++ {    i := i    go func() {        once.Do(func() {            fmt.Printf("first %d/n", i)        })    }()}

我們使用了 Do(func()) 方法來指定只有這部分代碼必須被執行一次。MVa28資訊網——每日最新資訊28at.com

sync.Cond

讓我們以最可能最少使用的原語 sync.Cond 結束。MVa28資訊網——每日最新資訊28at.com

它用于向 goroutine 發出信號(一對一)或向 goroutine(s) 廣播信號(一對多)。MVa28資訊網——每日最新資訊28at.com

假設我們有一個場景,需要通知一個 goroutine 共享切片的第一個元素已被更新。MVa28資訊網——每日最新資訊28at.com

創建一個 sync.Cond 需要一個 sync.Locker 對象(可以是 sync.Mutex 或 sync.RWMutex):MVa28資訊網——每日最新資訊28at.com

cond := sync.NewCond(&sync.RWMutex{})

接下來,讓我們編寫一個函數來顯示切片的第一個元素:MVa28資訊網——每日最新資訊28at.com

func printFirstElement(s []int, cond *sync.Cond) {    cond.L.Lock()    cond.Wait()    fmt.Printf("%d/n", s[0])    cond.L.Unlock()}

正如你所看到的,我們可以使用 cond.L 來訪問內部互斥鎖。一旦鎖被獲取,我們調用 cond.Wait(),它會阻塞直到收到信號。MVa28資訊網——每日最新資訊28at.com

現在回到主 goroutine。我們將通過傳遞一個共享切片和之前創建的 sync.Cond 來創建一個 printFirstElement 池。然后,我們調用一個 get() 函數,將結果存儲在 s[0] 中并發出一個信號:MVa28資訊網——每日最新資訊28at.com

s := make([]int, 1)for i := 0; i < runtime.NumCPU(); i++ {    go printFirstElement(s, cond)}i := get()cond.L.Lock()s[0] = icond.Signal()cond.L.Unlock()

這個信號將解除一個創建的 goroutine 的阻塞狀態,它將顯示 s[0]。MVa28資訊網——每日最新資訊28at.com

然而,如果我們退一步來看,我們可能會認為我們的代碼可能違反了 Go 最基本的原則之一:MVa28資訊網——每日最新資訊28at.com

不要通過共享內存來通信;相反,通過通信來共享內存。MVa28資訊網——每日最新資訊28at.com

MVa28資訊網——每日最新資訊28at.com

事實上,在這個例子中,最好使用一個通道來傳遞 get() 返回的值。MVa28資訊網——每日最新資訊28at.com

然而,我們也提到了 sync.Cond 還可以用于廣播信號。MVa28資訊網——每日最新資訊28at.com

讓我們修改上一個示例的結尾,將 Signal() 改為 Broadcast():MVa28資訊網——每日最新資訊28at.com

i := get()cond.L.Lock()s[0] = icond.Broadcast()cond.L.Unlock()

在這種情況下,所有的 goroutine 都會被觸發。MVa28資訊網——每日最新資訊28at.com

眾所周知,通道元素只會被一個 goroutine 捕獲。唯一模擬廣播的方式是關閉一個通道,但這不能重復使用。因此,盡管 頗具爭議,這無疑是一個有趣的特性。MVa28資訊網——每日最新資訊28at.com

還有一個值得提及的 sync.Cond 使用場景,也許是最重要的一個:MVa28資訊網——每日最新資訊28at.com

示例的 Go Playground 地址:https://play.golang.org/p/ap5qXF5DAg5MVa28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-34620-0.htmlGo 語言中 sync 包的近距離觀察

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

上一篇: 如何使用Python防止他人截取你的屏幕?這里有六種方法!

下一篇: 七個令人瞠目結舌的Python庫

標簽:
  • 熱門焦點
  • MIX Fold3包裝盒泄露 新機本月登場

    小米的全新折疊屏旗艦MIX Fold3將于本月發布,近日該機的真機包裝盒在網上泄露。從圖上來看,新的MIX Fold3包裝盒在外觀設計方面延續了之前的方案,變化不大,這也是目前小米旗艦
  • SpringBoot中使用Cache提升接口性能詳解

    環境:springboot2.3.12.RELEASE + JSR107 + Ehcache + JPASpring 框架從 3.1 開始,對 Spring 應用程序提供了透明式添加緩存的支持。和事務支持一樣,抽象緩存允許一致地使用各
  • 得物效率前端微應用推進過程與思考

    一、背景效率工程隨著業務的發展,組織規模的擴大,越來越多的企業開始意識到協作效率對于企業團隊的重要性,甚至是決定其在某個行業競爭中突圍的關鍵,是企業長久生存的根本。得物
  • 在線圖片編輯器,支持PSD解析、AI摳圖等

    自從我上次分享一個人開發仿造稿定設計的圖片編輯器到現在,不知不覺已過去一年時間了,期間我經歷了裁員失業、面試找工作碰壁,寒冬下一直沒有很好地履行計劃.....這些就放在日
  • 中國家電海外掘金正當時|出海專題

    作者|吳南南編輯|胡展嘉運營|陳佳慧出品|零態LT(ID:LingTai_LT)2023年,出海市場戰況空前,中國創業者在海外紛紛摩拳擦掌,以期能夠把中國的商業模式、創業理念、戰略打法輸出海外,他們依
  • 新電商三兄弟,“抖快紅”成團!

    來源:價值研究所作 者:Hernanderz 隨著內容電商的概念興起,抖音、快手、小紅書組成的&ldquo;新電商三兄弟&rdquo;成為業內一股不可忽視的勢力,給阿里、京東、拼多多帶去了巨大壓
  • 阿里大調整

    來源:產品劉有媒體報道稱,近期淘寶天貓集團啟動了近年來最大的人力制度改革,涉及員工績效、層級體系等多個核心事項,目前已形成一個初步的&ldquo;征求意見版&rdquo;:1、取消P序列
  • OPPO、vivo、小米等國內廠商Q2在印度智能手機市場份額依舊高達55%

    7月20日消息,據外媒報道,研究機構的報告顯示,在全球智能手機出貨量同比仍在下滑的大背景下,印度這一有潛力的市場也未能幸免,出貨量同比也有下滑,多家廠
  • 親歷馬斯克血洗Twitter,硅谷的苦日子在后頭

    文/劉哲銘  編輯/李薇  馬斯克再次揮下裁員大刀。  美國時間11月14日,Twitter約4400名外包員工遭解雇,此次被解雇的員工的主要工作為內容審核等。此前,T
Top 主站蜘蛛池模板: 噶尔县| 清镇市| 易门县| 博野县| 图木舒克市| 乐东| 兴安盟| 荃湾区| 定襄县| 盐山县| 黎平县| 阳山县| 旌德县| 宁波市| 三原县| 白玉县| 株洲市| 从江县| 玛沁县| 龙海市| 伊通| 同心县| 女性| 察哈| 宁阳县| 东源县| 莆田市| 香港 | 兰溪市| 永宁县| 锦州市| 开封县| 湘乡市| 日土县| 文成县| 晋宁县| 正阳县| 蒙阴县| 会宁县| 调兵山市| 孝昌县|