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

举报
我是小白呀iamarookie 发表于 2021/09/09 22:18:31 2021/09/09
2.3k+ 0 0
【摘要】 【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)

}

  
 

输出结果:

69980

  
 

我们可以看到, 输出的结果是 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)

}

  
 

输出结果:

100000

  
 

互斥锁

互斥锁 (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()
	
}

  
 

输出结果:

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

  
 

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

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

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

作者其他文章

评论(0

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

    全部回复

    上滑加载中

    设置昵称

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

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

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