Go语言中管理状态的主要机制是通过通道进行通信。在过去的文章中我们已经看到了这一点,例如工人池。 还有一些其他选项用于管理状态。 这里我们将使用sync/atomic
包来实现由多个goroutine
访问的原子计数器。
使用一个无符号整数表示计数器(正数)。
为了模拟并发更新,将启动50
个goroutine
,每个增量计数器大约是1
毫秒。
为了原子地递增计数器,这里使用AddUint64()
函数,在ops
计数器的内存地址上使用&
语法。
在增量之间等待一秒,允许一些操作累积。
为了安全地使用计数器,同时它仍然被其他goroutine
更新,通过LoadUint64
提取一个当前值的副本到opsFinal
。 如上所述,需要将获取值的内存地址&ops
给这个函数。
运行程序显示执行了大约40,000
次操作。
所有的示例代码,都放在
F:\worksp\golang
目录下。安装Go编程环境请参考:/tutorial/detail-5562.html
atomic-counters.go
的完整代码如下所示 -
package main import "fmt" import "time" import "sync/atomic" func main() { // We'll use an unsigned integer to represent our // (always-positive) counter. var ops uint64 = 0 // To simulate concurrent updates, we'll start 50 // goroutines that each increment the counter about // once a millisecond. for i := 0; i < 50; i++ { go func() { for { // To atomically increment the counter we // use `AddUint64`, giving it the memory // address of our `ops` counter with the // `&` syntax. atomic.AddUint64(&ops, 1) // Wait a bit between increments. time.Sleep(time.Millisecond) } }() } // Wait a second to allow some ops to accumulate. time.Sleep(time.Second) // In order to safely use the counter while it's still // being updated by other goroutines, we extract a // copy of the current value into `opsFinal` via // `LoadUint64`. As above we need to give this // function the memory address `&ops` from which to // fetch the value. opsFinal := atomic.LoadUint64(&ops) fmt.Println("ops:", opsFinal) }
执行上面代码,将得到以下输出结果 -
F:\worksp\golang>go run atomic-counters.go ops: 41360