Go by Example: Atomic Counters原子计数器

英文源地址
Go中管理状态的主要机制式通过channel通信.我们以worker pool为例可以看到这一点. 不过, 还有其他一些管理状态的选项. 在这里, 我们将看看如何使用sync/atomic包来处理多个goroutine访问的原子计数器.

package main

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

func main() {
    
    
	// 我们将使用一个无符号整数来表示(总是正的)计数器.
	var ops uint64

	// WaitGroup将帮助我们等待所有的协程完成它们的工作
	var wg sync.WaitGroup

	// 我们将启动50个协程, 每个协程将计数器递增1000次
	for i := 0; i < 50; i++ {
    
    
		wg.Add(1)

		// 为了自动增加计数器, 我们使用AddUint64,用&语法传递给它ops计数器的内存地址
		go func() {
    
    
			for c := 0; c < 1000; c++ {
    
    
				atomic.AddUint64(&ops, 1)
			}
			wg.Done()
		}()
	}
	// 等待所有协程都完成
	wg.Wait()
	// 现在访问ops是安全的, 因为我们直到没有其他协程正在写入它
	// 在原子地更新时安全地读取它们也是可能的, 使用像atomic.LoadUint64这样的函数
	fmt.Println("ops", ops)
}

我们预期会进行50000次操作. 如果我们使用非原子的ops++来增加计数器, 我们可能会得到一个不一样的数字, 在每次运行时都会有所变化, 因为协程会互相干扰.此外,当使用-race标志运行时, 我们将会遇到数据竞争失败.

$ go run atomic-counters.go
ops: 50000

接下来我们将看看互斥锁, 这是另一种管理状态的工具.

猜你喜欢

转载自blog.csdn.net/weixin_43547795/article/details/130873146