go - 如何在高并发系统中创建全局计数器
问题描述
我正在创建全局计数器,它可以在 goroutine 之间共享。提到这个问题,下面的代码可能会满足我的需求。
但是,如果有很多并发请求,是否会发生相同的数字分配给两个以上的 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
}
解决方案
您的问题的直接答案是:您粘贴的代码安全地更新了计数器,但没有安全地读取或重置它。
但是,与您链接到的问题中公认的答案相反,实现共享计数器的最简单、最有效的方法是使用atomic包。它可用于以原子方式递增几种常见类型。例子:
var globalCounter *int32 = new(int32)
// .. later in your code
currentCount := atomic.AddInt32(globalCounter, 1)
推荐阅读
- python - 分配错误之前引用的 Python
- python - 使用 groupby() 绘制销售趋势
- android - 使用具有隐式意图的 android Content Provider 泄漏数据
- python - 覆盖第三方应用程序 social-auth-app-django 使用的 create_user() 函数
- android - 使用编辑文本android停止滚动活动
- git - .gitignore 文件基于其内容
- podio - podio PodioApp::get 返回标签而不是 external_id
- django - 如何修复QuerySet'对象在django中没有属性'userrole_set'?
- java - 实现泛型类,得到 Activity.this 错误
- javascript - 将 DOM 元素 ID 传递给 JavaScript 函数