优化自增锁算法

This commit is contained in:
GoEdgeLab
2023-07-02 15:27:49 +08:00
parent 7a2d643906
commit cf5dd5ffea
2 changed files with 88 additions and 9 deletions

View File

@@ -1,6 +1,7 @@
package models
import (
"github.com/TeaOSLab/EdgeAPI/internal/zero"
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/dbs"
@@ -11,6 +12,10 @@ import (
type SysLockerDAO dbs.DAO
// concurrent transactions control
// 考虑到存在多个API节点的可能性容量不能太大也不能使用mutex
var sysLockerConcurrentLimiter = make(chan zero.Zero, 8)
func NewSysLockerDAO() *SysLockerDAO {
return dbs.NewDAO(&SysLockerDAO{
DAOObject: dbs.DAOObject{
@@ -117,6 +122,12 @@ func (this *SysLockerDAO) Increase(tx *dbs.Tx, key string, defaultValue int64) (
if tx == nil {
var result int64
var err error
sysLockerConcurrentLimiter <- zero.Zero{} // push
defer func() {
<-sysLockerConcurrentLimiter // pop
}()
err = this.Instance.RunTx(func(tx *dbs.Tx) error {
result, err = this.Increase(tx, key, defaultValue)
if err != nil {
@@ -142,11 +153,10 @@ func (this *SysLockerDAO) Increase(tx *dbs.Tx, key string, defaultValue int64) (
FindInt64Col(0)
}
// 读取当前版本号
func (this *SysLockerDAO) Read(tx *dbs.Tx, key string) (int64, error) {
return this.Query(tx).
Attr("key", key).
Result("version").
FindInt64Col(0)
}
}

View File

@@ -3,8 +3,10 @@ package models
import (
_ "github.com/go-sql-driver/mysql"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/types"
"sync"
"testing"
"time"
)
func TestSysLockerDAO_Lock(t *testing.T) {
@@ -25,22 +27,89 @@ func TestSysLockerDAO_Lock(t *testing.T) {
}
func TestSysLocker_Increase(t *testing.T) {
count := 100
wg := sync.WaitGroup{}
dbs.NotifyReady()
var count = 1000
var dao = NewSysLockerDAO()
value, err := dao.Read(nil, "hello")
if err != nil {
t.Fatal(err)
}
t.Log("before", value)
var locker = sync.Mutex{}
var allValueMap = map[int64]bool{}
var before = time.Now()
var wg = sync.WaitGroup{}
wg.Add(count)
for i := 0; i < count; i++ {
go func() {
go func(i int) {
defer wg.Done()
v, err := NewSysLockerDAO().Increase(nil, "hello", 0)
var key = "hello"
v, err := dao.Increase(nil, key, 0)
if err != nil {
t.Log("err:", err)
return
}
t.Log("v:", v)
}()
locker.Lock()
if allValueMap[v] {
t.Log("duplicated:", v)
} else {
allValueMap[v] = true
}
locker.Unlock()
//t.Log("v:", v)
_ = v
}(i)
}
wg.Wait()
t.Log("ok")
t.Log("cost:", time.Since(before).Seconds()*1000, "ms")
value, err = dao.Read(nil, "hello")
if err != nil {
t.Fatal(err)
}
t.Log("after", value, "values:", len(allValueMap))
}
func TestSysLocker_Increase_Performance(t *testing.T) {
dbs.NotifyReady()
var count = 1000
var dao = NewSysLockerDAO()
var before = time.Now()
var wg = sync.WaitGroup{}
wg.Add(count)
for i := 0; i < count; i++ {
go func(i int) {
defer wg.Done()
var key = "hello" + types.String(i%10)
v, err := dao.Increase(nil, key, 0)
if err != nil {
t.Log("err:", err)
return
}
//t.Log("v:", v)
_ = v
}(i)
}
wg.Wait()
t.Log("cost:", time.Since(before).Seconds()*1000, "ms")
}