教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Go并发编程之传统同步 — 原子操作

Go并发编程之传统同步 — 原子操作

发布时间:2022-02-05   编辑:jiaochengji.com
教程集为您提供Go并发编程之传统同步 — 原子操作等资源,欢迎您收藏本站,我们将为您提供最新的Go并发编程之传统同步 — 原子操作资源
<h2>前言</h2>

之前文章中介绍的互斥锁虽然能够保证同串行化,但是却保证不了执行过程中的中断。
要么成功、要么失败,没有中断的情况,我们叫它叫原子性,这种由硬件 CPU 提供支持的特性,是非常可靠的。

百度百科上关于原子操作的介绍。

<h2>原子操作</h2>

由 sync/atomic 包提供操作支持。

<h3>加法(add)</h3>

实现累加

<pre><code class="lang-go">func TestDemo1(t *testing.T) { var counter int64 = 0 for i := 0; i < 100; i { go func() { atomic.AddInt64(&counter, 1) }() } time.Sleep(2 * time.Second) log.Println("counter:", atomic.LoadInt64(&counter)) }</code></pre>

结果

<pre><code class="lang-go">=== RUN TestDemo1 2020/10/11 00:24:56 counter: 100 --- PASS: TestDemo1 (2.00s) PASS</code></pre><h3>减法(add)</h3>

对于做减法,是没有直接提供的方法的,而 Add(-1)这种是不能对 uint 类型使用的,可以通过补码的方式实现

<pre><code class="lang-go">func TestDemo2(t *testing.T) { var counter uint64 = 100 for i := 0; i < 100; i { go func() { atomic.AddUint64(&counter, ^uint64(-(-1)-1)) }() } time.Sleep(2 * time.Second) log.Println("counter:", atomic.LoadUint64(&counter)) }</code></pre>

结果

<pre><code class="lang-go">=== RUN TestDemo2 2020/10/11 00:32:05 counter: 0 --- PASS: TestDemo2 (2.00s) PASS</code></pre><h3>比较并交换(compare and swap,简称 CAS)</h3>

并发编程中,在没有使用互斥锁的前提下,对共享数据先取出做判断,再根据判断的结果做后续操作,必然是会出问题的,使用 CAS 可以避免这种问题。

<pre><code class="lang-go">func TestDemo3(t *testing.T) { var first int64 = 0 for i := 1; i <= 10000; i { go func(i int) { if atomic.CompareAndSwapInt64(&first, 0, int64(i)) { log.Println("抢先运行的是 goroutine", i) } }(i) } time.Sleep(2 * time.Second) log.Println("num:", atomic.LoadInt64(&first)) }</code></pre>

结果

<pre><code class="lang-go">=== RUN TestDemo3 2020/10/11 00:42:10 抢先运行的是 goroutine 3 2020/10/11 00:42:12 num: 3 --- PASS: TestDemo3 (2.01s) PASS</code></pre><h3>加载(load)</h3>

加载操作在进行时只会有一个,不会有其它的读写操作同时进行。

<pre><code class="lang-go">func TestDemo4(t *testing.T) { var counter int64 = 0 for i := 0; i < 100; i { go func() { atomic.AddInt64(&counter, 1) log.Println("counter:", atomic.LoadInt64(&counter)) }() } time.Sleep(2 * time.Second) }</code></pre><h3>存储(store)</h3>

存储操作在进行时只会有一个,不会有其它的读写操作同时进行。

<pre><code class="lang-go">func TestDemo5(t *testing.T) { var counter int64 = 0 for i := 0; i < 10; i { go func(i int) { atomic.StoreInt64(&counter, int64(i)) log.Println("counter:", atomic.LoadInt64(&counter)) }(i) } time.Sleep(2 * time.Second) }</code></pre><h3>交换(swap)</h3>

swap 方法返回被替换之前的旧值。

<pre><code class="lang-go">func TestDemo6(t *testing.T) { var counter int64 = 0 for i := 0; i < 10; i { go func(i int) { log.Println("counter old:", atomic.SwapInt64(&counter, int64(i))) }(i) } time.Sleep(2 * time.Second) }</code></pre>

结果

<pre><code class="lang-go">=== RUN TestDemo6 2020/10/11 00:43:36 counter old: 0 2020/10/11 00:43:36 counter old: 9 2020/10/11 00:43:36 counter old: 5 2020/10/11 00:43:36 counter old: 1 2020/10/11 00:43:36 counter old: 2 2020/10/11 00:43:36 counter old: 3 2020/10/11 00:43:36 counter old: 6 2020/10/11 00:43:36 counter old: 4 2020/10/11 00:43:36 counter old: 7 2020/10/11 00:43:36 counter old: 0 --- PASS: TestDemo6 (2.00s) PASS</code></pre><h3>原子值(value)</h3>

value是一个结构体,内部值定义为 interface{},所以它是可以接受任何类型的值。

第一次赋值的时候,原子值的类型就确认了,后面不能赋值其它类型的值。

<pre><code class="lang-go">func TestDemo7(t *testing.T) { var value atomic.Value var counter uint64 = 1 value.Store(counter) log.Println("counter:", value.Load()) value.Store(uint64(10)) log.Println("counter:", value.Load()) value.Store(100) // 引发 panic log.Println("counter:", value.Load()) time.Sleep(2 * time.Second) }</code></pre>

结果

<pre><code class="lang-go">=== RUN TestDemo7 2020/10/11 10:14:58 counter: 0 2020/10/11 10:14:58 counter: 10 --- FAIL: TestDemo7 (0.00s) panic: sync/atomic: store of inconsistently typed value into Value [recovered] panic: sync/atomic: store of inconsistently typed value into Value ... Process finished with exit code 1</code></pre>

您可能感兴趣的文章:
常见的导致mysql中文乱码问题
mysql中文乱码问题解决方法总结
mysql导入导出数据时中文乱码的解决办法
整理的.NET高效开发的25款工具【值得收藏】
Go并发编程之传统同步 — 原子操作
go并发编程笔记
goroutine 的同步(第一部分)
图解 Go 并发编程
goroutine 的同步(第二部分)
15 Go语言并发1——Goroutine

[关闭]
~ ~