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 提供了一种创建更细粒度锁定的机制,以帮助释放更多全局锁来处理其他任务。