Go原子计数器实例


Go语言中管理状态的主要机制是通过通道进行通信。在过去的文章中我们已经看到了这一点,例如工人池。 还有一些其他选项用于管理状态。 这里我们将使用sync/atomic包来实现由多个goroutine访问的原子计数器。

使用一个无符号整数表示计数器(正数)。

为了模拟并发更新,将启动50goroutine,每个增量计数器大约是1毫秒。

为了原子地递增计数器,这里使用AddUint64()函数,在ops计数器的内存地址上使用语法。

在增量之间等待一秒,允许一些操作累积。

为了安全地使用计数器,同时它仍然被其他goroutine更新,通过LoadUint64提取一个当前值的副本到opsFinal。 如上所述,需要将获取值的内存地址&ops给这个函数。

运行程序显示执行了大约40,000次操作。

所有的示例代码,都放在 F:\worksp\golang 目录下。安装Go编程环境请参考:http://www.yiibai.com/go/go_environment.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

匿名

发表评论

匿名网友