bounded 'mutex pools' 用于同步实体行为
bounded 'mutex pools' for synchronized entity behaviour
我有一个功能
type Command struct {
id Uuid
}
handleCommand(cmd Command)
{
entity := lookupEntityInDataBase(cmd.Uuid)
entity.handleCommand(cmd)
saveEntityInDatabase(entity)
}
但是这个函数可以并行调用,并且假设实体是非线程安全的,这会导致实体状态和将保存在数据库中的状态变得活跃。
在此函数的开头和结尾处进行简单的互斥锁定可以解决此问题,但会导致过于悲观的同步,因为不同实例的实体(即不同的 uuid)应该被允许并行处理它们的命令。
另一种方法是保留 map[uuid]sync.Mutex
的 Map,如果之前没有遇到 uuid,则创建一个新的互斥锁,并以线程安全的方式创建它。但是,这将导致在运行时遇到的所有 uuid 的映射可能会无限增长。
我想过之后清理互斥锁,但是这样做是线程安全的,并且意识到另一个线程可能已经在等待互斥锁打开了很多蠕虫罐头。
我希望我错过了一个非常简单而优雅的解决方案。
没有真正优雅的解决方案。这是一个使用频道的版本:
var m map[string]chan struct{}
var l sync.Mutex
func handleCommand(cmd Command) {
for {
l.Lock()
ch, ok:=m[cmd.Uuid]
if !ok {
ch=make(chan struct{})
m[uuid]=ch
defer func() {
l.Lock()
delete(m,cmd.Uuid)
close(ch)
l.Unlock()
}()
l.Unlock()
break
}
l.Unlock()
<-ch
}
entity := lookupEntityInDataBase(cmd.Uuid)
entity.handleCommand(cmd)
saveEntityInDatabase(entity)
}
Moby 项目有库之类的东西,请参阅 https://github.com/moby/locker
单行说明是,
locker 提供了一种创建更细粒度锁定的机制,以帮助释放更多全局锁来处理其他任务。
我有一个功能
type Command struct {
id Uuid
}
handleCommand(cmd Command)
{
entity := lookupEntityInDataBase(cmd.Uuid)
entity.handleCommand(cmd)
saveEntityInDatabase(entity)
}
但是这个函数可以并行调用,并且假设实体是非线程安全的,这会导致实体状态和将保存在数据库中的状态变得活跃。
在此函数的开头和结尾处进行简单的互斥锁定可以解决此问题,但会导致过于悲观的同步,因为不同实例的实体(即不同的 uuid)应该被允许并行处理它们的命令。
另一种方法是保留 map[uuid]sync.Mutex
的 Map,如果之前没有遇到 uuid,则创建一个新的互斥锁,并以线程安全的方式创建它。但是,这将导致在运行时遇到的所有 uuid 的映射可能会无限增长。
我想过之后清理互斥锁,但是这样做是线程安全的,并且意识到另一个线程可能已经在等待互斥锁打开了很多蠕虫罐头。
我希望我错过了一个非常简单而优雅的解决方案。
没有真正优雅的解决方案。这是一个使用频道的版本:
var m map[string]chan struct{}
var l sync.Mutex
func handleCommand(cmd Command) {
for {
l.Lock()
ch, ok:=m[cmd.Uuid]
if !ok {
ch=make(chan struct{})
m[uuid]=ch
defer func() {
l.Lock()
delete(m,cmd.Uuid)
close(ch)
l.Unlock()
}()
l.Unlock()
break
}
l.Unlock()
<-ch
}
entity := lookupEntityInDataBase(cmd.Uuid)
entity.handleCommand(cmd)
saveEntityInDatabase(entity)
}
Moby 项目有库之类的东西,请参阅 https://github.com/moby/locker
单行说明是,
locker 提供了一种创建更细粒度锁定的机制,以帮助释放更多全局锁来处理其他任务。