data-structures - 带范围的 Golang 并发 map 访问

标签 data-structures go concurrency

我有一张 map ,其中包含需要在清除 map 之前释放的对象。我很想在遍历 map 时迭代 map 并删除/释放对象。

这是一个模拟示例 https://play.golang.org/p/kAtPoUgMsq

由于迭代 map 的唯一方法是通过范围,我将如何同步多个生产者和多个消费者?

我不想读取锁定 map ,因为这会使迭代期间无法删除/修改键。

最佳答案

有很多方法可以让您从 map 中清理内容,而无需访问不雅的 map 。对您的应用程序有效的方法很大程度上取决于它在做什么。

0) 工作时只需锁定 map 即可。如果 map 不是太大,或者您有一些延迟容忍度,它可以快速完成工作(就花费在上面的时间而言),您可以继续考虑其他事情。如果以后变成问题,你可以再回到问题上来。

1) 将对象或指针复制出来并在持有锁的同时清除 map ,然后在后台释放对象。如果问题是释放本身的缓慢会使锁保持很长时间,那么这是解决此问题的简单解决方法。

2) 如果高效读取基本上是最重要的,请使用 atomic.Value。这使您可以用新的不同 map 完全替换一张 map 。如果写入基本上是您工作负载的 0%,那么高效的读取会平衡每次更改时创建新映射的成本。这种情况很少见,但确实会发生,例如,encoding/gob 具有以这种方式管理的类型的全局映射。

3) 如果这些都不能满足您的所有需求,请调整存储数据的方式(例如,对 map 进行分片)。自己用 16 个映射和哈希键替换您的映射,以决定一个事物属于哪个映射,然后您可以一次锁定一个分片,以进行清理或任何其他写入。

还有释放和使用之间的竞争问题:goroutine A 从 map 中获取一些东西,B 清除 map 并释放东西,A 使用释放的东西。

一种策略是在您使用或释放​​每个值时锁定它;那么你需要锁而不是全局锁。

另一个是容忍种族的后果,如果它们是已知的并且不是灾难性的;例如,net.Conns 的文档明确允许并发访问,因此关闭正在使用的连接可能会导致对其的请求出错,但不会导致未定义的应用行为。但是,您必须真正确定自己知道自己要进入的内容,因为many benign-seeming races aren't .

最后,也许您的应用程序已经确保不会释放正在使用的对象,例如对对象有一个安全维护的引用计数,并且只释放未使用的对象。那么,当然,您不必担心。

尝试以某种方式用 channel 替换这些锁可能很诱人,但我看不到任何 yield 。 很好当您可以设计您的应用程序时主要考虑进程之间的通信而不是共享数据,但是当您确实有共享数据时,假装没有用处。排除对共享数据的不安全访问是锁的用途。

关于data-structures - 带范围的 Golang 并发 map 访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34080734/

相关文章:

algorithm - 摊销分析和竞赛题,有什么问题吗?

go - Go接口(interface){}与内置类型直接比较 : Why does this work?

objective-c - 什么是nsoperation?如何使用它?

algorithm - 如何有效地存储具有高度冗余值的矩阵

c# - LinkedList 比 List 迭代更快?

algorithm - 如何将二叉堆转换为二项式队列

mongodb - 使用官方 mongo-go-driver 进行正确的通配符多字段查询

debugging - 打印 golang 结构时如何忽略 String() 方法?

Golang 异步和 CPU 使用率

java - 如何迁移到 Java App Engine 中的并发请求?