【发布时间】:2020-06-11 17:35:10
【问题描述】:
我正在开发一个包含多个例程的应用程序。处理器接收一个 ID(字符串)并执行一些操作。 ID 可能重复,我不希望多个例程在另一个例程处理一个 ID 时处理它。
我为此使用了一个同步互斥体映射。
type cache struct{
sync.Mutex
ids map[string]struct{}
}
func(c *cache) addIfNotPresent(string)bool{
c.Lock()
defer c.Unlock()
if _, ok := c.ids[id]; ok{
return false
}
c.ids[id] = struct{}{}
return true
}
func(c *cache) delete(string){
c.Lock()
defer c.Unlock()
delete(c.ids, id)
}
我的处理器有这个地图的一个实例。现在我的流程看起来像这样
func process(string){
ok := cache.addIfNotPresent(id)
if !ok{
return
}
defer cache.delete(id)
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
err := doOne(ctx)
if err {
return err
}
...
return nil
}
使用 defer 以便无论处理器中发生什么,都会删除 id。
有时(并非总是)该值不会从地图中逐出。从日志/指标来看,我确定这不是错误情况,但过程功能已完成,并且密钥未从地图中逐出。
我在这里遗漏了互斥或延迟的任何行为吗?
【问题讨论】:
-
您至少应该发布
addIfNotPresent()和delete()实现。 -
代码看起来不错。您确定您发布了实际代码吗?缺少 arg 名称,这让我认为我们在这里看到的内容可能缺少更多。
-
我没有复制粘贴。但我确信这正是我所拥有的。
-
证据表明并非如此。 defer() 不会失败。
-
我编辑了一下。
doOne函数接受上下文。我通过超时的上下文并推迟取消。有什么区别吗?