专栏首页ccf19881030的博客Go by Example 中文版: 互斥锁

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ubuntu10.04使用小结

    最近由于要学习Linux下的C和C++编程,我选择了比较好安装的桌面版的Linux发行版本Ubuntu10.04 LTS(ubuntu-10.04-deskt...

    ccf19881030
  • go语言逐行读取和写入文件

    前面一篇博客讲到nodejs使用readline逐行读取和写入文件 今天使用go语言实现从输入文件中读取每行数据,然后将每行字段组合成SQL插入脚本,然后逐行...

    ccf19881030
  • Java 之数据类型

    基本类型与引用类型的区别: 1.基本类型与引用类型的组成 基本类型是一个单纯的数据类型,它表示的是一个具体的数字、字符或一个布尔值,例如100、'M'和tr...

    ccf19881030
  • TensorFlow什么的都弱爆了,强者只用Numpy搭建神经网络

    很多同学入门机器学习之后,直接用TensorFlow调包实现神经网络,对于神经网络内在机理知之甚少。

    大数据文摘
  • TensorFlow什么的都弱爆了,强者只用Numpy搭建神经网络

    很多同学入门机器学习之后,直接用TensorFlow调包实现神经网络,对于神经网络内在机理知之甚少。

    abs_zero
  • 数据分析的3个常用方法:数据趋势、对比和细分分析

    一个产品,如果你不能衡量它,你就不能了解它,自然而然,你就无法改进它。数据说到底,就是这样一个工具——通过数据,我们可以衡量产品,可以了解产品,可以在数据驱动下...

    叫我龙总
  • CVE-2019-0232-ApacheTomca远程执行代码漏洞复现

    2019年4月13号,Apache Tomcat 9.0.18版本公告中提到,本次更新修复了一个代号为CVE-2019-0232的漏洞。

    墙角睡大觉
  • CentOS系统自动下载RPM包及其所有依赖的包

    程序员同行者
  • 后渗透阶段开始

    在后渗透测试阶段我们主要的目标就是上传工具,权限提升,擦除攻击痕迹,安装持久化后门

    意大利的猫
  • PyTorch 中Datasets And DataLoaders的使用 | PyTorch系列(十二)

    在这篇文章中,我们将看到如何使用Dataset和DataLoader 的PyTorch类。

    AI算法与图像处理

扫码关注云+社区

领取腾讯云代金券