如何在高并发系统的Golang中创建全局计数器

I'm creating global counter, which can be shared between goroutines. Referring to this question, following code may satisfy my needs.

However if there ware lots of concurrent requests, could it happen that the same number is assigned to more than two goroutines? If so how can I avoid this?

Thanks!

complementary comment) This question is different from the link I pasted, as what I want to know about is how I can avoid duplication using channel counter. if the only possible solution is other implementation like sync.Mutex or atomic, I'll use it. however, according to the link (again), channel seems to be the best option. Any comment or answer really helpful. thanks in advance. I'm new to multithread coding and also go, might be silly question. sorry for that.

package main

import (
    "fmt"
    "time"
)

var counter int
var counter_chan chan int

func main() {
    counter_chan = make(chan int, 100)

    counter = 0

    go func() {
        for {
            select {
            case chanc := <-counter_chan:
                counter += chanc
                fmt.Printf("%d 
", counter)
            }
        }
    }()

    for i := 0; i < 10; i++ {
        go AddCounter(counter_chan)
    }

    time.Sleep(time.Second)
    fmt.Printf("Total Count is ... %d 
", GetCount())

}

func AddCounter(ch chan int) {
    ch <- 1
}

func GetCount() int {
    return counter
}

func ResetCount() {
    if counter > 8190 {
        counter = 0
    }
}

-- Edit 05/14 2018

Assume following code is thread-safe for getting and resetting value. Am I right?

package main

import (
    "fmt"
    "time"
)

var counter int
var addCounterChan chan int
var readCounterChan chan int

func main() {
    addCounterChan = make(chan int, 100)
    readCounterChan = make(chan int, 100)

    counter = 0

    go func() {
        for {
            select {
            case val := <-addCounterChan:
                counter += val
                if counter > 5 {
                    counter = 0
                }
                readCounterChan <- counter
                fmt.Printf("%d 
", counter)
            }
        }
    }()

    for i := 0; i < 10; i++ {
        go AddCounter(addCounterChan)
    }

    time.Sleep(time.Second)

    for i := 0; i < 10; i++ {
        fmt.Printf("Total Count #%d is ... %d 
", (i + 1), GetCount(readCounterChan))
    }

}

// Following two functions will be implemented in another package in real case.
func AddCounter(ch chan int) {
    ch <- 1
}

func GetCount(ch chan int) int {
    r := <-ch
    return r
}

The direct answer to your question is: The code you've pasted updates the counter safely, but doesn't read or reset it safely.

Contrary to the accepted answer in the question you linked to, however, the easiest, most efficient way to implement a shared counter is with the atomic package. It can be used to atomically increment several common types. Example:

var globalCounter *int32 = new(int32)

// .. later in your code
currentCount := atomic.AddInt32(globalCounter, 1)

Use a sync.Mutex to create a counter with add, get and reset operations as shown in the question.

type counter struct {
    mu sync.Mutex
    n  int
}

func (c *counter) Add() {
    c.mu.Lock()
    c.n++
    c.mu.Unlock()
}

func (c *counter) Get() int {
    c.mu.Lock()
    n := c.n
    c.mu.Unlock()
    return n
}

func (c *counter) Reset() {
    c.mu.Lock()
    if c.n > 8190 {
        c.n = 0
    }
    c.mu.Unlock()
}

If the reset function is not needed, then use the sync/atomic.

type counter struct {
    n int32
}

func (c *counter) Add() {
    atomic.AddInt32(&c.n, 1)
}

func (c *counter) Get() int {
    return int(atomic.LoadInt32(&c.n))
}