Go语言现代web开发15 Mutex 互斥锁

Channels are mainly used for goroutines that need to communicate with each other, in order for them to exchange some values. In a situation when multiple goroutines need to update the same value, we must prevent simultaneous access to that value. This concept is known as mutual exclusion.

通道主要用于需要相互通信的程序,以便它们交换一些值。在多个例程需要更新同一值的情况下,必须防止同时访问该值。这个概念被称为互斥。

Why simultaneous access is important? Well, without it, concurrency concepts can be violated. Let us imagine a situation where two goroutines need to duplicate the value of a variable. The initial value of the variable is 5, so the final result should be 20 (5 * 2 * 2).

为什么同时访问很重要? 如果没有它,并发概念就会被违反。让我们想象这样一种情况:两个例程需要复制一个变量的值。变量的初始值是5,所以最终结果应该是20(5 * 2 * 2)。

Without mutual exclusion next scenario is possible. The first goroutne reads the value of variable (5), in the meantime, the second goroutine reads the value of variable (5) and updates the value, so now the value of variable is equal to 10. The first goroutine will now duplicate the value, but it holds the old variable value (5), so the final result will not be 20, it will be 10 which is not crrect.

没有相互排斥,下一种情况是可能的。第一个线程读取变量(5)的值,与此同时,第二个线程读取变量(5)的值并更新该值,因此现在变量的值等于10。第一个例程现在将复制该值,但它保留旧的变量值(5),因此最终结果将不是20,而是10,这是不正确的。

Go programming language provides mutual exclution through the standard library with type Mutex from sync package and two methods: Lock() and Unlock(). Only one goroutine can access code between calls of these two methods at a time. Here is a mutex solution for the previously described problem.

Go编程语言通过sync包中的Mutex类型标准库和Lock()和Unlock()两种方法提供互斥。在调用这两个方法之间,一次只能有一个程序访问代码。下面是前面描述的问题的互斥锁解决方案。

完整代码:

go 复制代码
package main

import (
	"fmt"
	"sync"
	"time"
)

type MutualExclusion struct {
	mutex sync.Mutex
	value int
}

func (me *MutualExclusion) Double() {
	me.mutex.Lock()
	me.value *= 2
	me.mutex.Unlock()
}

func main() {
	me := MutualExclusion{value: 5}
	go me.Double()
	go me.Double()

	time.Sleep(time.Second)
	fmt.Println(me.value)
}

Sleep method is called in order to prevent method Print() to be executed before both goroutines complete execution. If we use the Lock() method to lock a certain part of the code, we must use the Unlock() method to unlock it. If we leave the code locked, other goroutines cannot access them. It is a good practice to combine the all of Unlock() method with defer, so we can be sure that the code will be unlocked no matter what.

调用Sleep方法是为了防止在两个程序完成执行之前执行方法Print()。如果我们使用Lock()方法锁定代码的某个部分,我们必须使用Unlock()方法解锁它。如果我们将代码锁定,其他例程就不能访问它们。将Unlock()方法与defer结合使用是一个很好的做法,这样我们就可以确保代码无论如何都将被解锁。

上面案例的详细中文注释版本:

go 复制代码
package main

import (
	"fmt"
	"sync"
	"time"
)

type MutualExclusion struct {
	mutex sync.Mutex // 互斥锁
	value int        // 要操作的值
}

// Double 定义一个方法,让 value 可以并发的乘以 2
func (me *MutualExclusion) Double() {
	me.mutex.Lock() // 上锁
	me.value *= 2
	me.mutex.Unlock() // 解锁
}

func main() {
	// 在两个 goroutine 中,分别让 value 乘以 2
	// value = 5  ===> 5 x 2 x 2 = 20

	me := MutualExclusion{value: 5}

	// 并发调用,开启两个 goroutine
	go me.Double()
	go me.Double()

	time.Sleep(time.Second) // 让协程能够执行完毕
	fmt.Println(me.value)
}

mutex 的使用建议:

go 复制代码
// Double 定义一个方法,让 value 可以并发的乘以 2
func (me *MutualExclusion) Double() {
	// 最佳实践: 在 lock 之后立马接上 defer unlock
	// 这样,不管我们代码发生什么样的错误,我们始终能够保证锁的安全(上锁,解锁都被执行)
	me.mutex.Lock()         // 上锁
	defer me.mutex.Unlock() // 解锁
	me.value *= 2
}

在上锁以后, 使用 defer mutex.Unlock() 释放锁.

相关推荐
CodeCraft Studio1 天前
PDF处理控件Aspose.PDF教程:使用 Python 将 PDF 转换为 Base64
开发语言·python·pdf·base64·aspose·aspose.pdf
零点零一1 天前
VS+QT的编程开发工作:关于QT VS tools的使用 qt的官方帮助
开发语言·qt
2501_915918411 天前
Web 前端可视化开发工具对比 低代码平台、可视化搭建工具、前端可视化编辑器与在线可视化开发环境的实战分析
前端·低代码·ios·小程序·uni-app·编辑器·iphone
程序员的世界你不懂1 天前
【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇
java·前端·数据库
索迪迈科技1 天前
网络请求库——Axios库深度解析
前端·网络·vue.js·北京百思可瑞教育·百思可瑞教育
gnip1 天前
JavaScript二叉树相关概念
前端
lingchen19061 天前
MATLAB的数值计算(三)曲线拟合与插值
开发语言·matlab
gb42152871 天前
java中将租户ID包装为JSQLParser的StringValue表达式对象,JSQLParser指的是?
java·开发语言·python
一朵梨花压海棠go1 天前
html+js实现表格本地筛选
开发语言·javascript·html·ecmascript
蒋星熠1 天前
Flutter跨平台工程实践与原理透视:从渲染引擎到高质产物
开发语言·python·算法·flutter·设计模式·性能优化·硬件工程