如何在 Golang 中使用互斥鎖 (Mutex)?
為了理解 Go 中的 **互斥鎖 (mutex)** 在編寫更出色和準確的併發程式中發揮的重要作用,我們首先必須瞭解稱為 **競爭條件 (Race Conditions)** 的概念。讓我們首先了解什麼是競爭條件,以及如何編寫包含競爭條件的併發程式,以及如何隨後在該程式中引入 **互斥鎖 (mutex)** 以使其準確。
競爭條件
**競爭條件** 是一種狀態,其中多個 **goroutine** 嘗試訪問和修改同一資源。可能的情況是,一個 **goroutine** 試圖增加某個特定變數的值,而另一個 **goroutine** 同時試圖訪問它,或者可能多個 **goroutine** 同時試圖增加某個特定變數的值。
需要注意的是,只有當我們為特定變數提供了 **寫入** 許可權時,才會出現競爭條件。如果只有 **讀取** 許可權可用,那麼就不會有任何問題,因為即使多個 **goroutine** 試圖讀取單個值,讀取也不會導致任何問題。
示例 1
現在假設我們想為一家本地銀行編寫一個應用程式,該銀行只支援將金額存入銀行的單一功能。可能有多個人同時嘗試存入金額,我們可以藉助多個 **goroutine** 來表示這種情況。
請考慮下面顯示的程式碼,該程式碼描述了這種情況。
package main
import (
"fmt"
"sync"
)
var (
balance int
wg sync.WaitGroup
)
func Deposit(amount int) {
balance = balance + amount
wg.Done()
}
func main() {
wg.Add(3)
go Deposit(100)
go Deposit(200)
go Deposit(300)
wg.Wait()
fmt.Println("Balance is:", balance)
}在上面的示例中,我們可以看到除了 **main** 函式 goroutine 之外還有三個 **goroutine**。這三個 **goroutine** 都在呼叫 **deposit** 函式,因此存在競爭條件,因為我們尚未處理它。
可以使用 **"race"** 標誌確認競爭條件的存在。
go run -race main.go
**注意** - **race 標誌** 用於檢查任何 Golang 程式碼是否存在競爭條件。
輸出
Balance is: 600
為了使程式碼更準確並消除此競爭條件,我們使用 **互斥鎖 (Mutex)**,也稱為 **互斥**,它可以防止併發程序在給定程序執行其他任務時訪問關鍵資料。
示例 2
請考慮下面顯示的程式碼,我們在其中在上述程式碼中使用了 **互斥鎖 (Mutex)** 來消除競爭條件。
package main
import (
"fmt"
"sync"
)
var (
balance int
wg sync.WaitGroup
mu sync.Mutex
)
func Deposit(amount int) {
mu.Lock()
defer mu.Unlock()
balance = balance + amount
wg.Done()
}
func main() {
wg.Add(3)
go Deposit(100)
go Deposit(200)
go Deposit(300)
wg.Wait()
fmt.Println("Balance is:", balance)
}
輸出
現在,如果我們執行命令 **go run -race main.go**,那麼我們將看不到任何提到的競爭條件。我們得到的輸出如下所示。
Balance is: 600
資料結構
網路
關係型資料庫管理系統 (RDBMS)
作業系統
Java
iOS
HTML
CSS
Android
Python
C 程式設計
C++
C#
MongoDB
MySQL
Javascript
PHP