go构建高并发计数器

功能需求

  1. 计数器基本功能:支持递增、递减和获取当前计数值。
  2. 并发安全:确保多个协程同时访问计数器时不会出现数据竞争。
  3. 高效性能:使用适当的同步机制,优化性能。
  4. 重置功能:支持计数器重置为初始值。
  5. 持久化(可选) :支持将计数值持久化到文件或数据库中。
  6. 统计接口:提供API或方法获取计数器访问统计信息(如最大并发量)。

实施计划

  1. 技术调研 :对比 sync.Mutexsync.RWMutexsync/atomic 以及 sync.Map 的性能差异,选择最佳实现方式。
  2. 数据结构设计:定义计数器结构体,封装计数值和同步机制。
  3. 并发安全实现:采用选定的同步方案,完成增、减、获取操作。
  4. 压力测试:编写并发测试代码,验证线程安全性和性能。
  5. API接口封装:提供简单的对外接口,便于调用。
  6. 持久化实现(可选) :提供数据持久化接口(如JSON文件或SQLite数据库)。
  7. 统计接口实现:记录并发请求总数和最大并发量。
  8. 文档编写与代码整理:撰写代码使用文档及示例。

代码编写步骤

1. 数据结构设计

首先,定义一个计数器结构体,使用 sync/atomic 保证并发安全。

go 复制代码
go
複製編輯
package counter

import (
	"sync/atomic"
)

type Counter struct {
	value int64
}

func NewCounter() *Counter {
	return &Counter{}
}

2. 基本功能实现

提供递增、递减和获取当前值的方法。

scss 复制代码
go
複製編輯
// Increment 增加计数器值
func (c *Counter) Increment() {
	atomic.AddInt64(&c.value, 1)
}

// Decrement 减少计数器值
func (c *Counter) Decrement() {
	atomic.AddInt64(&c.value, -1)
}

// Get 获取当前计数器值
func (c *Counter) Get() int64 {
	return atomic.LoadInt64(&c.value)
}

3. 重置功能

增加一个重置方法。

scss 复制代码
go
複製編輯
// Reset 重置计数器
func (c *Counter) Reset() {
	atomic.StoreInt64(&c.value, 0)
}

4. 并发测试代码

编写测试代码,验证线程安全性。

go 复制代码
go
複製編輯
package main

import (
	"fmt"
	"sync"
	"counter"
)

func main() {
	c := counter.NewCounter()
	var wg sync.WaitGroup

	// 并发1000个协程进行递增
	for i := 0; i < 1000; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			c.Increment()
		}()
	}

	wg.Wait()
	fmt.Println("最终计数值:", c.Get())
}

5. 持久化(可选)

可以将计数器值写入文件。

go 复制代码
go
複製編輯
import (
	"os"
	"fmt"
)

func (c *Counter) SaveToFile(filename string) error {
	file, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer file.Close()

	_, err = file.WriteString(fmt.Sprintf("%d", c.Get()))
	return err
}

6. 统计接口(可选)

增加统计并发访问量。

go 复制代码
go
複製編輯
type CounterWithStats struct {
	Counter
	totalAccess int64
}

func (cs *CounterWithStats) Increment() {
	atomic.AddInt64(&cs.totalAccess, 1)
	cs.Counter.Increment()
}

func (cs *CounterWithStats) GetTotalAccess() int64 {
	return atomic.LoadInt64(&cs.totalAccess)
}

性能测试结果

可以使用 go test -bench 进行基准测试。

示例基准代码:

go 复制代码
go
複製編輯
package counter

import "testing"

func BenchmarkIncrement(b *testing.B) {
	c := NewCounter()
	for i := 0; i < b.N; i++ {
		c.Increment()
	}
}

总结

  1. 代码线程安全 ✅
  2. 支持高并发 ✅
  3. 性能较优(sync/atomicsync.Mutex 更快) ✅
  4. 可扩展功能:统计、持久化 ✅

收获

  1. atomic和sync.Mutex区别,atomic适合简单的原子计算,Mutex锁适合复杂的临界区操作
  2. go的结构体类继承的原理,和其他语言不一样,go的类继承其实是把其他结构体组合成了新的结构体
  3. benchmark测试的基础使用方法
相关推荐
forever234 小时前
自定义go日志接口的实现
go
DemonAvenger4 小时前
深入Go并发编程:Goroutine性能调优与实战技巧全解析
设计模式·架构·go
考虑考虑8 小时前
Golang 使用定时任务(robfig/cron/v3)
后端·程序员·go
一个热爱生活的普通人11 小时前
深入解析Go语言container/list:双向链表的实现与应用
后端·面试·go
十字路口的火丁12 小时前
Golang 中的 Restful API 请求客户端 resty 简介(类似 Java 中的 Jersey)
后端·go
寻月隐君1 天前
gogen:一键生成 Go 项目,开发者的效率利器
后端·go·github
HappyChan1 天前
kakfa生产者消费者实践
云原生·kafka·go
小白白白_1 天前
开工一个月,我自己造了一个编程语言!
go·编程语言
forever231 天前
go实现带超时控制的API调用
go
寻月隐君1 天前
Go语言中的变量与常量:深入理解与实战指南
后端·go·github