广告
返回顶部
首页 > 资讯 > 后端开发 > GO >Go语言并发之原子操作详解
  • 960
分享到

Go语言并发之原子操作详解

摘要

目录修改赋值与读取比较并交换小结代码中的加锁操作因为涉及内核态的上下文切换会比较耗时、代价比较高。针对基本数据类型我们还可以使用原子操作来保证并发安全,因为原子操作是Go语言提供的方

代码中的加操作因为涉及内核态的上下文切换会比较耗时、代价比较高。针对基本数据类型我们还可以使用原子操作来保证并发安全,因为原子操作是Go语言提供的方法它在用户态就可以完成,因此性能比加锁操作更好。Go语言中原子操作由内置的标准库sync/atomic 提供。

大多数情况下我们都是针对基本数据类型进行数据操作,能不加锁就不加锁。

首先很多人都不相信基本类型并发修改会出现竞态问题。不妨尝试一下,并发加一。

var wg sync.WaitGroup
for i := 0; i < 10000; i++ {
wg.Add(1)
go func () {
defer wg.Done()
xInt32++
}()
}
wg.Wait()
print(xInt32)

无论输出多少次都无法达到10000,之所以如此就是因为此处的加1操作并不是原子的,都是先取当前值,加1,再赋值,会出现覆盖的情况。

修改

修改是最常用到的。

func modify(delta int32) {
atomic.AddInt32(&xInt32, delta)
atomic.AddInt64(&xInt64, int64(delta))
atomic.AddUint32(&xuInt32, uint32(delta))
atomic.AddUint64(&xuInt64, uint64(delta))
}

我们忽略了Uintptr的讨论,这是内存地址的整数表示,是用来存地址内容的,暂时没有遇到过指针的数据计算。

var wg sync.WaitGroup
for i := 0; i < 10000; i++ {
wg.Add(1)
go func () {
defer wg.Done()
//xInt32++
modify(1)
}()
}
wg.Wait()
print(xInt32)

改为原子操作后,发现每次运行都可以得到预期的结果10000

赋值与读取

在并发情况下,读取到某个变量后,在使用时变量内容可能会被篡改,所以使用原子读取。 在并发情况下,为某个变量赋值的时候,必须要防止读取到写入一半的错误值,所以要用原子写入。

var xInt32 int32
atomic.StoreInt32(&xInt32, 100)
println(xInt32)
v := atomic.LoadInt32(&xInt32)
println(v)

输出

100
100

就目前而言,原子读写都是为了防止读写一半导致数据错误,但我无法复现这种错误的场景,假如你可以复现请在本文底部放留言。

var v atomic.Value
v.Store([]int{})
fmt.Println(v.Load().([]int))

也可以存储其他任意类型,但如果使用到类似append扩容原变量的语句,而不是使用直接替换的话,原子操作也是会失效的。

比较并交换

以下是节选自《Go并发编程实战》一书中的例子,比较并交换(Compare And Swap)简称CAS,是乐观锁的核心思想,所以简单介绍一下。

var xInt32 int32
for {
    v := atomic.LoadInt32(&xInt32)
    if atomic.CompareAndSwapint32(&xInt32, v, v+100) {
        break
    }
}
print(xInt32)
  • 这里一种无锁的结构,是一种思路,在需要改变数据的时候,反复判断数据是否和原数据一致
  • 一致时替换,不一致时说明被它处修改,则跳过
  • 在不创建互斥量和不形成临界区的情况下,完成并发安全的值替换操作。

小结

1.最常用原子操作中的修改、基本类型的值赋值,其他不常用

2.在其他类型出现并发的时候尽可能使用sync包提供的并发安全的类型,下一节讲。

3.通过通信共享内存;不要通过共享内存进行通信。尽量使用通道。

到此这篇关于Go语言并发之原子操作详解的文章就介绍到这了,更多相关Go语言原子操作内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

您可能感兴趣的文档:

--结束END--

本文标题: Go语言并发之原子操作详解

本文链接: https://www.lsjlt.com/news/176179.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Go语言并发之原子操作详解
    目录修改赋值与读取比较并交换小结代码中的加锁操作因为涉及内核态的上下文切换会比较耗时、代价比较高。针对基本数据类型我们还可以使用原子操作来保证并发安全,因为原子操作是Go语言提供的方...
    99+
    2022-12-29
    Go语言 并发 原子操作 Go语言 原子操作 Go语言 并发
  • Java并发编程之原子操作类详情
    JUC包提供了一系列的原子性操作类,这些类都是使用非阻塞算法CAS实现的,相比使用锁实现原子性操作者在性能上有很大提升。JUC包中含有AtomicInteger、AtomicLong...
    99+
    2022-11-13
  • 详解go语言的并发
    目录1、启动go语言的协程2、runtime.Goexit()方法。立即终止当前的协程3、runtime.GOMAXPROCS()表示go使用几个cpu执行代码4、管道定义和创...
    99+
    2022-06-07
    详解go语言 GO 并发 go语言
  • GO语言并发之好用的sync包详解
    目录sync.Map 并发安全的Mapsync.Once 只执行一次sync.Cond 条件变量控制小结sync.Map 并发安全的Map 反例如下,两个Goroutine分别读写。...
    99+
    2022-12-29
    GO语言 并发 sync包 GO语言 sync包 GO sync包
  • Go语言中并发的工作原理
    一、Go语言中Goroutine的基本原理 Go语言里的并发指的是能让某个函数独立于其他函数运行的能力。 Go语言的goroutine是一个独立的工作单元, Go 语言的并发同步模型...
    99+
    2022-11-13
  • 详解Java并发编程之原子类
    目录原子数组AtomicIntegerArray原子更新器AtomicIntegerFieldUpdater原子累加器LongAdder原子数组 原子数组有AtomicInteger...
    99+
    2023-05-18
    Java并发原子类 Java并发
  • Go语言学习之文件操作方法详解
    目录引言1. 打开和关闭文件2. 读取文件2.1 defer 语句2.2 手动宕机处理2.3 打开文件并获取内容2.4 bufio 读取文件2.5 ioutil 读取文件2.6 读取...
    99+
    2022-11-13
  • Go语言操作Excel利器之excelize类库详解
    目录前言Excelize简介安装导出 Excel 文档读取Excel文档小结前言 在开发中一些需求需要通过程序操作excel文档,例如导出excel、导入excel、向excel文档...
    99+
    2022-11-11
  • Go语言原子操作及互斥锁的区别
    目录增或减比较并交换(Compare And Swap)载入与存储交换原子值原子操作与互斥锁的区别原子操作就是不可中断的操作,外界是看不到原子操作的中间状态,要么看到原子操作已...
    99+
    2022-06-07
    GO 互斥 原子 原子操作 互斥锁 go语言
  • 详解C语言之操作符
    目录1.加减乘2.除(/)注意:3.取余(%)注意:4.移位操作符(>> <<)注意5.位操作符(| ,& ,^)6.逻辑操作符(&&...
    99+
    2022-11-12
  • GO的锁和原子操作的示例详解
    目录GO的锁和原子操作分享锁是什么锁是用来做什么的互斥锁互斥锁 - 解决问题读写锁我们先来写一个读写锁的DEMO自旋锁和互斥锁的区别如何选择锁啥是原子操作总结GO的锁和原子操作分享 ...
    99+
    2023-02-24
    GO锁 原子操作 GO锁 GO 原子操作
  • Go语言学习笔记之文件读写操作详解
    目录文件写文件读小结文件操作比较多,分为几篇来写吧。首先是文件的读写,在平时的工程化操作中使用最多。 文件写 样例代码如下 package main import ( "...
    99+
    2022-11-13
  • 详解Go语言微服务开发框架之Go chassis
    目录引言架构获取配置配置项形态配置运行时热加载例子引言 https://github.com/go-chassis/go-chassis是一个微服务开发框架,而微服务开发框架带来的其...
    99+
    2022-11-12
  • Go语言开发保证并发安全实例详解
    目录什么是并发安全?Mutex悲观锁乐观锁版本号机制CAS互斥锁读写互斥锁什么是并发安全? 在高并发场景下,进程、线程(协程)可能会发生资源竞争,导致数据脏读、脏写、死锁等问题,为了...
    99+
    2022-11-11
  • 详解Go语言中的数据库操作
    目录原生SQL方式ORM方式数据库是应用开发中必须要掌握的技巧,通常在数据库开发过程中,会有两种不同的方式: 直接使用SQL语句,这种方式下,直接编写SQL,简单直观,但是可维护性较...
    99+
    2023-02-07
    Go语言数据库操作 Go语言数据库 Go 数据库
  • 详解Go语言中的Slice链式操作
    目录示例原理实现示例 首先模拟一个业务场景,有订单、产品、自定义订单三个结构体,订单中包含多个产品: type Order struct { Id string Pr...
    99+
    2023-05-15
    Go Slice链式操作 Go Slice操作 Go Slice
  • 详解C语言之文件操作(上)
    目录什么是文件程序文件数据文件文件名文件类型文件缓冲区文件指针 文件的打开和关闭输入和输出总结什么是文件 磁盘上的文件就是文件。 在程序设计中,我们一般谈的文件有两种:程序...
    99+
    2022-11-12
  • 详解C语言之文件操作下)
    目录文件的随机读写fseek函数ftell函数rewind函数文件结束判定feof函数和ferror函数总结文件的随机读写 之前的函数只能实现顺序读写,而实现随机读写需用fseek函...
    99+
    2022-11-12
  • Go语言原子操作及互斥锁的区别是什么
    本篇内容介绍了“Go语言原子操作及互斥锁的区别是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!原子操作就是不可中断的操作,外界是看不到原...
    99+
    2023-06-22
  • Go语言中map使用和并发安全详解
    目录1 map使用1.1 map定义1.2 map的使用和概念1.3 map的容量1.4 map的使用1.4.1 map的遍历1.4.2 map的删除和断言1.5 map的坑2 并发...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作