我有一张地图,其中包含需要在清除地图之前释放的对象.当我走过它时,我很想迭代地图并删除/释放对象.
这是一个模拟示例 https://play.golang.org/p/kAtPoUgMsq
由于迭代地图的唯一方法是通过范围,我如何同步多个生产者和多个消费者?
我不想读取锁定地图,因为这样会在迭代过程中删除/修改键不可能.
有很多方法可以从map
没有活动的地图访问中清理东西.适用于您的应用程序取决于它正在做什么.
0)只需在处理地图时锁定地图.如果地图不是太大,或者你有一些延迟容忍度,它可以快速完成工作(就你花在它上面的时间而言),你可以继续思考其他的东西.如果以后出现问题,那么您可以回过头来解决问题.
1)复制对象或指针并在握住锁定时清除地图,然后在后台释放对象.如果问题在于释放本身的缓慢会使锁保持很长时间,这就是简单的解决方法.
2)如果有效读取基本上都是重要的,请使用atomic.Value
.这使您可以用一个新的不同的地图完全替换一个地图.如果写入基本上是工作负载的0%,则高效读取会平衡每次更改时创建新映射的成本.这种情况很少见,但它发生了,例如,encoding/gob
有一个以这种方式管理的全球类型地图.
3)如果这些都不能满足您的需求,请调整存储数据的方式(例如,将地图分片).用自己的16个地图和散列键替换你的地图,以决定一个东西属于哪个地图,然后你可以一次锁定一个碎片,进行清理或任何其他写入.
在发布和使用之间也存在争用的问题:goroutine A从地图中获取内容,B清除地图并释放内容,A使用发布的内容.
一种策略是在您使用或释放它时锁定每个值; 那么你需要锁而不是全局锁.
另一种是如果他们知道并且不是灾难性的话,就能容忍种族的后果; 例如,net.Conn
其文档明确允许对s的并发访问,因此关闭正在使用的连接可能会导致对它的请求出错,但不会导致未定义的应用程序行为.你必须确定你知道你正在进入的是什么,但是,因为很多良性看似的比赛都没有.
最后,也许您的应用程序已经确保不会释放任何正在使用的对象,例如,对象上有一个安全维护的引用计数,并且只释放未使用的对象.然后,当然,你不必担心.
尝试用某种方式用通道替换这些锁可能很诱人,但我没有看到任何收益.如果你能够设计你的应用程序主要是考虑流程之间的通信而不是共享数据,这很好,但是当你有共享数据时,没有必要假装.排除对共享数据的不安全访问是锁的用途.