【Golang】✔️走进 Go 语言✔️ 第二十课 原子操作 & 互斥体

举报
我是小白呀iamarookie 发表于 2021/09/09 22:18:31 2021/09/09
【摘要】 【Golang】✔️走进 Go 语言✔️ 第二十课 概述协程存在的问题原子操作互斥锁 概述 Golang 是一个跨平台的新生编程语言. 今天小白就带大家一起携手走进 Golang 的世界....

【Golang】✔️走进 Go 语言✔️ 第二十课

概述

Golang 是一个跨平台的新生编程语言. 今天小白就带大家一起携手走进 Golang 的世界. (第 20 课)

在这里插入图片描述

协程存在的问题

当大量的协程并发的时候, 会产生资源抢占冲突.

例子:

package main

import (
	"fmt"
	"time"
)

func main() {

	// 定义原子变量整数
	var ops uint64 = 0

	// 创建一坨协程
	for i := 0; i < 10; i++ {
		go func() {
			for j := 0; j < 10000; j++ {
			    // 线程冲突, 数据不精确
				ops += 1
			}
		}()
	}

	// 等待
	time.Sleep(time.Second * 5)

	// 调试输出
	fmt.Println(ops)

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

输出结果:

69980

  
 
  • 1

我们可以看到, 输出的结果是 69980, 而非 100000, 原因是线程冲突导致数据不精确.

原子操作

atomic 提供的原子操作使得我们能够确保任一时刻只有一个协程 (go routine) 对变量进行操作. 善用 atomic 能够避免程序中出现大量的锁操作.

在这里插入图片描述

例子:

package main

import (
	"fmt"
	"sync/atomic"
	"time"
)

func main() {

	// 定义原子变量整数
	var ops uint64 = 0

	//
	for i := 0; i < 10; i++ {
		go func() {
			for j := 0; j < 10000; j++ {
				// 避免线程冲突	
				atomic.AddUint64(&ops, 1)
			}
		}()
	}

	// 等待
	time.Sleep(time.Second * 5)

	// 调试输出
	fmt.Println(ops)

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

输出结果:

100000

  
 
  • 1

互斥锁

互斥锁 (Mutex) 用于主动控制元素的变量在同一时间只能被一个协程访问.

Mutex 有两个方法:

  • func (*Mutex) Lock: Lock 方法锁住 m, 如果 m 已经加锁, 则阻塞到 m 解锁
  • func (*Mutex) Unlock: Unlock 方法解锁 m, 如果 m 未加锁会导致运行时错误

在这里插入图片描述

例子:

package main

import (
	"fmt"
	"math/rand"
	"sync"
	"sync/atomic"
	"time"
)


func main() {
	var state = make(map[int]int)  // 状态
	var mutex = &sync.Mutex{}  // 互斥锁
	var readops uint64 = 0  // 读取数据
	var writeops uint64 = 0  // 写入数据


	// 循环读取
	for i := 0; i < 100; i++ {
		go func() {
			total := 0
			for {

				key := rand.Intn(5)
				mutex.Lock()  // 加锁
				total += state[key]  // 数据叠加
				mutex.Unlock()  // 解锁

				atomic.AddUint64(&readops, 1)  // 记录读取次数

				time.Sleep(time.Millisecond)
			}
		}()
	}

	// 循环写入
	for i := 0; i < 10; i++ {
		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)
			}
		}()
	}

	// 休眠1秒
	time.Sleep(time.Second * 1)

	// 调试输出
	read := atomic.LoadUint64(&readops)
	write := atomic.LoadUint64(&writeops)
	fmt.Println(read)
	fmt.Println(write)

	mutex.Lock()
	fmt.Println(state)
	mutex.Unlock()
	
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66

输出结果:

5179
519
map[0:36 1:67 2:62 3:86 4:68]

  
 
  • 1
  • 2
  • 3

文章来源: iamarookie.blog.csdn.net,作者:我是小白呀,版权归原作者所有,如需转载,请联系作者。

原文链接:iamarookie.blog.csdn.net/article/details/119769852

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。