Go原子計數器範例


Go語言中管理狀態的主要機制是通過通道進行通訊。在過去的文章中我們已經看到了這一點,例如工人池。 還有一些其他選項用於管理狀態。 這裡我們將使用sync/atomic包來實現由多個goroutine存取的原子計數器。

使用一個無符號整數表示計數器(正數)。

為了模擬並行更新,將啟動50goroutine,每個增量計數器大約是1毫秒。

為了原子地遞增計數器,這裡使用AddUint64()函式,在ops計數器的記憶體地址上使用語法。

在增量之間等待一秒,允許一些操作累積。

為了安全地使用計數器,同時它仍然被其他goroutine更新,通過LoadUint64提取一個當前值的副本到opsFinal。 如上所述,需要將獲取值的記憶體地址&ops給這個函式。

執行程式顯示執行了大約40,000次操作。

所有的範例程式碼,都放在 F:\worksp\golang 目錄下。安裝Go程式設計環境請參考:/2/23/798.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