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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在高度并发的系统中创建全局计数器相关的知识,希望对你有一定的参考价值。

我正在创建全局计数器,可以在goroutine之间共享它。参考此question,以下代码可以满足我的需求。

但是,如果有很多并发请求,那么将相同的编号分配给两个以上的goroutine会发生吗?如果可以,我该如何避免呢?

谢谢!

补充评论]这个问题与我粘贴的链接不同,因为我想知道的是如何避免使用通道计数器重复。如果唯一可行的解​​决方案是sync.Mutex或atomic等其他实现,我将使用它。但是,根据链接(再次),频道似乎是最佳选择。任何评论或答案确实有帮助。提前致谢。我对多线程编码还是陌生的,这可能是一个愚蠢的问题。对此表示抱歉。

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 \n", counter)
            
        
    ()

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

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



func AddCounter(ch chan int) 
    ch <- 1


func GetCount() int 
    return counter


func ResetCount() 
    if counter > 8190 
        counter = 0
    

-编辑2018年5月14日

假定以下代码对于获取和重置值是线程安全的。我说的对吗?

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 \n", 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 \n", (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

答案

您的问题的直接答案是:您安全地粘贴了updates计数器的代码,但是没有安全地读取或重置它。

与您链接到的问题中的公认答案相反,但是,实现共享计数器的最简单,最有效的方法是使用atomic程序包。它可以用于原子地递增几种常见类型。示例:

var globalCounter *int32 = new(int32)

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

使用sync.Mutex创建具有添加,获取和重置操作的计数器,如问题所示。

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()

如果不需要重置功能,请使用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))

以上是关于如何在高度并发的系统中创建全局计数器的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Access 2000 中关闭报告中的单词自动更改,如高度、宽度和计数

如何根据行创建日期在 PostgreSQL 中创建自定义序列?

如何在包含图像和计数帖子的页面中创建列表标签

如何在 SQL 2008 R2 的表中创建 AutoCounter 列?

如何在 Spark Scala 中的 Schema RDD [从案例类中创建] 中查找重复项以及相应的重复计数?

python 在python中创建计数器