【问题标题】:Create thread-safe cache of disposable objects创建一次性对象的线程安全缓存
【发布时间】:2013-12-16 08:54:50
【问题描述】:

我必须创建一次性对象的线程安全缓存。我怎么看:

  1. 我有一些数据类,我想缓存,例如 MyData
  2. 我正在为 MyData 创建一些集合(例如 ConcurrentDictionary)
  3. 我有使用某个键创建 MyData 新实例的方法。
  4. 当我需要获取某个键的 MyData 时,我会检查它是否存在于我的存储中 - 然后从集合中使用它,否则创建新实例并将其放入集合中
  5. 我有一些事件,当我应该使缓存无效时。在此事件中,我清除存储空间。

问题是 MyData 是一次性的。我不知道什么时候应该调用 Dispose 方法。在 clear-cache 事件上清除集合时,我无法调用 Dispose 方法,因为某些线程可以立即使用 MyData 的此实例。

我应该选择什么模式?

【问题讨论】:

  • 如果您的对象在许多消费者之间共享,那么谁调用Dispose 并不重要;所有消费者必须合作,让事情顺利进行。也许你应该准备好赶上ObjectDisposedException
  • 对象是同一类型吗?
  • @LasseV.Karlsen 它有什么区别,它们都是 IDissposable 的相同类型?

标签: c# multithreading caching idisposable


【解决方案1】:

在这种情况下,当缓存的消费者应该能够使用缓存中的项目完成当前操作时,并发收集没有多大意义。你真的需要在这里同步。

您可以在这里做的最明显的事情是使用ReaderWriteLockSlim 和常规Dictionary<TKey, TValue> 的包装器。

当有人想要使用缓存中的项目时,它会获得读取权限。当有人想要修改缓存(添加一个项目,或者完全使缓存无效)时,它会获得一个写访问权限(因此,写入器不能使缓存无效,直到最后一个读取器不会释放锁)。

当您刚刚捕获ObjectDisposedException 时,另一种选择是考虑方法。但这种方法假设当前操作可以从外部中断。

【讨论】:

  • 这与处置有什么关系?
【解决方案2】:

我认为您应该封装缓存机制,并且没有人应该调用 dispose 包装字典的对象应该在没有外部干预的情况下进行(单例模式在这里会很好,并且对字典的所有访问都应该被锁定,on如果您使缓存无效,只需再次将其锁定并处理它并清除它。如果您需要有关单例的帮助,请告诉我。

【讨论】:

  • 谢谢回复!主要问题,在我当前的设计缓存类中不能准确地说是否有人使用这个 MyData 实例。所以我不能处理它。现在我想我会为线程创建一些方法,这样它们就可以在开始和结束 MyData 使用时通知缓存类。因此,在事件发生时,我将清除集合,处理所有未使用的实例,然后释放繁忙的项目,当它们空闲时。
  • 这就是为什么单例和锁但忘记锁的原因,使用@dennis建议的方法与 ReaderWriteLockSlim 看起来更网络。
【解决方案3】:

如果对象在逻辑上是不可变的,创建起来有些昂贵,并且已知不消耗不可替代的资源而仅消耗少量的可替代资源;如果跟踪对它们的所有引用不切实际,您可以考虑使用短弱引用缓存。这种情况将是我认为“依赖”最终确定是合理的少数情况之一,因为在任何给定时间只有一个与给定键匹配的对象将永远存在于“易受攻击”队列(需要清理的对象列表)之外.这种方法的一个优点是,如果您避免复活已经有资格进行终结的对象,那么您的代码在大多数情况下不必过多担心线程问题。您必须定期清除关联的弱引用已失效的条目,并注意缓存条目在被识别为失效后可能会被新对象更新的可能性,但 GC 应确保对象不要在任何人使用它们时清理它们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多