如何在 Golang 中使用互斥锁?
为了理解为什么Go中的互斥锁在编写更好、更准确的并发程序方面发挥着重要作用,我们必须首先了解称为竞争条件的概念。让我们首先了解什么是竞态条件,以及如何编写具有竞态条件的并发程序以及如何在该程序中引入互斥量以使其准确。
竞争条件
一个竞争条件是在多一个条件够程试图访问和修改相同的资源。可能是一个goroutines试图增加一个特定变量的值而另一个goroutines试图同时访问它,或者可能就像多个goroutines试图增加特定变量的值同时。
应该注意的是,只有当我们为特定变量提供了写入权限时,才会出现竞争条件。如果只有读取权限可用,那么就不会有任何问题,因为读取不会引起任何问题,即使多个goroutine试图读取单个值。
示例1
现在让我们假设我们要为本地银行编写一个应用程序,该银行仅支持将金额存入银行的单一功能。可能有多个人同时尝试存入金额,我们可以在多个goroutines的帮助下表示这种情况。
考虑下面显示的描述这种情况的代码。
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) }
在上面的例子中,我们可以看到有三个够程比其他主要功能够程。这三个goroutine正在调用存款函数,因此,存在竞争条件,因为我们还没有处理它。
可以借助“race”标志来确认竞争条件的存在。
go run -race main.go
注意-竞赛标志用于检查任何Golang代码是否具有竞赛条件。
输出结果
余额为: 600
为了使代码更准确并消除这种竞争条件,我们使用了互斥,也称为互斥,它可以防止并发进程在给定进程执行另一个任务时访问关键数据。
示例2
考虑下面显示的代码,其中我们在上面的代码中使用了互斥锁来移除竞争条件。
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) }输出结果
现在,如果我们运行命令gorun-racemain.go,那么我们将看不到任何提到的竞争条件。我们得到的输出如下所示。
余额为: 600