最近需要一种相同的key就加锁,不同的key就并行处理的锁,golang标准库中都是比较粗粒度的锁,无法满足需求,通过搜索发现可以根据sync.map实现基于Key值的锁
参考资料 go - Golang - lock per value - Stack Overflow
package main
import (
"fmt"
"sync"
"time"
)
var km KeyedMutex
type KeyedMutex struct {
mutexes sync.Map // Zero value is empty and ready for use
}
func (m *KeyedMutex) Lock(key string) func() {
value, _ := m.mutexes.LoadOrStore(key, &sync.Mutex{})
mtx := value.(*sync.Mutex)
mtx.Lock()
return func() { mtx.Unlock() }
}
func main() {
wg := sync.WaitGroup{}
km := KeyedMutex{}
for _, job := range []struct {
key string
data string
}{
{key: "abc", data: "123"},
{key: "abc", data: "456"},
{key: "def", data: "123"},
{key: "def", data: "456"},
} {
var job = job
wg.Add(1)
go func() {
defer wg.Done()
unlock := km.Lock(job.key)
defer unlock()
fmt.Printf("%s:%s mutex acquired\n", job.key, job.data)
time.Sleep(time.Second * 3) // To ensure some goroutines visibly block
fmt.Printf("%s:%s done\n", job.key, job.data)
}()
}
wg.Wait()
}
执行结果示例:
def:456 mutex acquired
abc:456 mutex acquired
abc:456 done
abc:123 mutex acquired
def:456 done
def:123 mutex acquired
def:123 done
abc:123 done
相同的key 总是前一个done 后一个才会acquired