首頁 > 後端開發 > Golang > 學到了!將緩衝 channel 當做 Mutex 來使用

學到了!將緩衝 channel 當做 Mutex 來使用

發布: 2023-08-08 16:21:14
轉載
1379 人瀏覽過


作為Go 官方套件的一部分,sync 套件有下面這段聲明:

sync 套件提供了基本的同步原語,例如互斥鎖。除了 Once 和 WaitGroup 類型之外,大多數其他類型都是為底層函數庫準備的。透過 channel 和通訊更好地完成更高層級的同步.

在你能找到的關於允許並發存取的絕大多數例子中,很多都是使用互斥鎖來解決問題。然而,幾乎很少有範例給我們看如何使用 channel 提供同步機制。所以,這篇文章我們就來討論下。

互斥鎖的特性

為了讓互斥鎖起作用,存取共享變數時需要加鎖,操作完成之後需要解鎖。相同的互斥鎖不允許多次加鎖,以免出現競態條件。

無緩衝channel 及其不足之處

如果沒有接收方,發送者將會阻塞;相同地,如果沒有發送方,接收者將會阻塞。基於這個特性,所以我們不能將無緩衝的 channel 作為鎖定來使用。

我們來看看緩衝 channel 是否可以當做互斥鎖來使用。

緩衝為1 的channel 的特性及其可取之處

緩衝大小為1 的channel 具有如下的特性:如果緩衝滿了,發送時將會阻塞;如果快取騰空,發送時就會解除阻塞。

顯然,這種channel 的阻塞特性是可取的,與互斥鎖的特性做個對比:

緩衝滿時<--> 上鎖

緩衝騰空<--> 解鎖

我們一起透過程式碼示範下這個特性。

示範:如何將緩衝channel 當作「鎖」 來使用

我們假設有一列名字需要寫入到檔案中,每個名字都需要連續寫1000 次,且不允許不同名字出現交叉狀況。

package main
import (
 "errors"
 "fmt"
 "os"
 "sync"
)
func main() {
 file, err := os.Create("record.txt")

 defer func() {
  if err := recover(); err != nil {
   fmt.Printf("Error encounter: %w", err)
  }
  file.Close()
 }()
 if err != nil {
  panic(errors.New("Cannot create/open file"))
 }
 ss := []string{ //string slice literals
  "James",
  "Avery",
  "Peter",
  "John",
  "Beau",
 }
 chanLock := make(chan int, 1) //1
 var wg sync.WaitGroup
 for _, str := range ss { //2
  wg.Add(1) //amended thanks to response from Wang
  //Sheng
  go func(aString string) {

   chanLock <- 1 //3
   for i := 0; i < 1000; i++ {
    file.WriteString(aString + "\n")
   }
   <-chanLock //4
   wg.Done() //5
  }(str) //pass by value
 }
 wg.Wait()
}
登入後複製

在上面的程式碼中,//1 我們建立了緩衝為 1 的 channel。 //2 我們建立了個數與名字數量相同的 goroutine。 //3 相當於加鎖,//4 相當於解鎖,這樣就實現了多 goroutine 之間同步地將名字寫入到 record.txt 文件,但每次只會有一個 goroutine 操作該文件。

要注意的是,我們透過 WaitGroup 來保證子 goroutine 完成任務之前,主協程不會退出。

希望這篇文章對你有幫助,enjoy coding!

#

以上是學到了!將緩衝 channel 當做 Mutex 來使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:Golang菜鸟
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板