功能需求
- 计数器基本功能:支持递增、递减和获取当前计数值。
- 并发安全:确保多个协程同时访问计数器时不会出现数据竞争。
- 高效性能:使用适当的同步机制,优化性能。
- 重置功能:支持计数器重置为初始值。
- 持久化(可选) :支持将计数值持久化到文件或数据库中。
- 统计接口:提供API或方法获取计数器访问统计信息(如最大并发量)。
实施计划
- 技术调研 :对比
sync.Mutex
、sync.RWMutex
、sync/atomic
以及sync.Map
的性能差异,选择最佳实现方式。 - 数据结构设计:定义计数器结构体,封装计数值和同步机制。
- 并发安全实现:采用选定的同步方案,完成增、减、获取操作。
- 压力测试:编写并发测试代码,验证线程安全性和性能。
- API接口封装:提供简单的对外接口,便于调用。
- 持久化实现(可选) :提供数据持久化接口(如JSON文件或SQLite数据库)。
- 统计接口实现:记录并发请求总数和最大并发量。
- 文档编写与代码整理:撰写代码使用文档及示例。
代码编写步骤
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()
}
}
总结
- 代码线程安全 ✅
- 支持高并发 ✅
- 性能较优(
sync/atomic
比sync.Mutex
更快) ✅ - 可扩展功能:统计、持久化 ✅
收获
- atomic和sync.Mutex区别,atomic适合简单的原子计算,Mutex锁适合复杂的临界区操作
- go的结构体类继承的原理,和其他语言不一样,go的类继承其实是把其他结构体组合成了新的结构体
- benchmark测试的基础使用方法