Go by Example 中文版: 互斥锁
时间:2022-07-24
本文章向大家介绍Go by Example 中文版: 互斥锁,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
Go by Example 中文版: 互斥锁
在前面的例子中,我们看到了如何使用原子操作来管理简单的计数器。 对于更加复杂的情况,我们可以使用一个互斥锁 来在 Go 协程间安全的访问数据。 示例代码如下:
// Go by Example 中文:互斥锁
// https://books.studygolang.com/gobyexample/mutexes/
// 在前面的例子中,我们看到了如何使用原子操作来管理简单的计数器。
// 对于更加复杂的情况,我们可以使用一个互斥锁来在 Go 协程间安全的访问数据。
package main
import (
"fmt"
"math/rand"
"sync"
"sync/atomic"
"time"
)
func main() {
// state 是一个map
var state = make(map[int]int)
// 这里的 mutex 将同步对 state 的访问。
var mutex = &sync.Mutex{}
// 我们会持续追踪读写操作的数量。
// readOps 将记录我们对 state 的读操作次数
var readOps uint64
// writeOps 将记录我们对 state 的写操作次数
var writeOps uint64
// 这里我们运行100个Go协程来重复读取state
for r := 0; r < 100; r++ {
go func() {
total := 0
for {
/*
每次循环读取,我们使用一个键来进行访问,Lock() 这个 mutex 来确保对 state 的独占访问,
读取选定的键的值,Unlock() 这个mutex,并且 ops 值加 1。
*/
key := rand.Intn(5)
mutex.Lock()
total += state[key]
mutex.Unlock()
atomic.AddUint64(&readOps, 1)
/*
在下次读取前等到片刻。
*/
time.Sleep(time.Millisecond)
}
}()
}
// 同样的,我们运行10个Go协程来模拟写入操作,使用和读取相同的模式
for w := 0; w < 10; w++ {
go func() {
for {
key := rand.Intn(5)
val := rand.Intn(100)
mutex.Lock()
state[key] = val
mutex.Unlock()
atomic.AddUint64(&writeOps, 1)
time.Sleep(time.Millisecond)
}
}()
}
// 让这 10 个 Go 协程对 state 和 mutex 的操作运行 1 s。
time.Sleep(time.Second)
// 获取并输出最终的操作计数。
readOpsFinal := atomic.LoadUint64(&readOps)
fmt.Println("readOps:", readOpsFinal)
wrtieOpsFinal := atomic.LoadUint64(&writeOps)
fmt.Println("writeOps:", wrtieOpsFinal)
// 对 state 使用一个最终的锁,显示它是如何结束的。
mutex.Lock()
fmt.Println("state:", state)
mutex.Unlock()
}
运行这个程序,显示我们进行了大约 90,000 次 mutex 同步的 state 操作。
$ go run mutexes.go
readOps: 83285
writeOps: 8320
state: map[1:97 4:53 0:33 2:15 3:2]
我在自己的Windows10下的GoLand下运行的结果截图如下图所示:
接下来我们将看一下,只使用协程和通道, 如何实现相同的任务状态管理。
下一个例子: [状态协程](https://gobyexample-cn.github.io/stateful-goroutines)
@mmcgrana 编写 | everyx 翻译 | 项目地址 | license
- 如何做一个小程序口令红包功能
- 使用思维导图,优雅的完成自己的代码
- 移动端布局攻略
- nginx反向代理https网站 并实现网站的注册和登录功能
- 通过nginx GeoIP模块 限制某些国家地区访问网站
- CDN加速下通过nginx获取网站访客真实ip
- linux centos7服务器使用密钥登录ssh同时禁止root密码登录
- linux nginx服务器安装verynginx防止CC攻击
- linux nginx安装HttpGuard防止CC攻击
- wordpress您的主机禁用了mail()函数 SMTP邮件通知解决方法
- 我的编程之路:知识管理与知识体系
- UTF-8 为什么会比 UTF-16 浪费?
- 码农也要学算法
- 19 个常用的 JavaScript 简写方法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- uninstalling vim-minimal 同时也卸载了 sudo 解决方法
- 大点干!早点散----------深入剖析缓存加速--squid(反向代理与ACL访问控制以及sarg日志)
- JVM的Xms和Xmx参数设置为相同值有什么好处?
- 【CVPR 2020】一种新的门控通道注意力转换单元
- 5个好用的 CSS 函数
- java1.8中Object类源码分析
- 多线程基础(六):Object的wait方法以及notify与notifyAll的区别
- Day15:反转链表
- Day16:合并两个排序的链表
- 大厂面试爱问的「调度算法」,20 张图一举拿下
- Day17:树的子结构
- 多线程基础(七):关于HotSpot中notify方法不具备随机性的证明
- Day18:二叉树的镜像
- ksubdomain 无状态域名爆破工具
- Day19:顺时针打印矩阵