【问题标题】:Asynchronous, Thread-Safe Collection Implementing INotifyCollectionChanged实现 INotifyCollectionChanged 的​​异步线程安全集合
【发布时间】:2014-06-11 01:07:11
【问题描述】:

我使用的是 Silverlight 5.0,需要实现 IList<T> 和 IList。我的集合将用于不断地在其内部集合中添加和删除项目,并且 UI 将具有绑定到集合的元素。出于性能原因,我不希望每次集合更改时都呈现 UI,因为我希望对集合进行“组”更改,然后引发集合更改事件。我还希望能够使用 Task.Factory 方法来做到这一点,以保持一切异步。有没有人看到任何如何实现这一目标的好例子?

【问题讨论】:

  • Caliburn Micro 有一个 Bindable Collection,其属性为 IsNotifying,可以关闭和打开。我没有在多线程互斥环境中使用它。但是,值得一试。

标签: c# silverlight task-parallel-library


【解决方案1】:

线程安全、可观察的集合在设计上是有问题的。例如,如果您更改集合,并且引发事件,而正在处理该事件,则可以在另一个线程上更改集合。结果,刚刚被告知添加了一个项目的处理程序可能已经过时了(该项目可能已经消失了)。

或者,您是否考虑过在集合更改时将immutable collection 与事件一起使用?它本质上是线程安全的,如果您正确应用它,就不会受到上述设计问题的影响。它可能不符合您对该应用的要求——从问题中很难判断。

【讨论】:

  • 处理程序可能在过期后调用的事实不应被视为问题。处理程序处理这样的事情并不难,没有理由不应该为它们准备一个写得体面的处理程序。一个更大的问题是,当事件处理程序已经运行时,可能会向集合中添加一些东西。通常,调用SomeCollection.Add 的代码有权假定所有事件处理程序在它返回之前都已触发,但强加这样的语义会产生死锁的可能性。
【解决方案2】:

我建议的方法是为可能需要更新 UI 的集合的不同方面设置各种标志。如果集合中的某些内容发生更改并且未设置特定标志,请设置它并在提供的控件和委托上使用Control.BeginInvoke(使用Interlocked 或锁定以确保标志测试和设置在线程中完成-安全时尚)。 UI 更新方法应该在执行更新之前测试并清除适当的标志;如果执行了任何更新,则该方法应循环并重新测试所有标志,直到完成,而无需执行任何更新。

使用这种方法,应该能够避免通过BeginUpdate 排队的待处理操作数量过多。可能会有一些多余的更新,但一般不会太多。在某些情况下,让控件的代码限制每秒执行的更新次数可能会有所帮助;如果更新例程循环次数过多,请启动计时器并禁用更新,直到计时器到期。如果计时器到期需要更新,则执行更新并重新启动计时器;如果它过期并且不需要更新,则终止计时器。

试图让对集合的每一个更改都反映在“更新”事件中可能会适得其反。只需确保对显示的最后一次更新完全发生在对集合的最后一次更改之后。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-15
    • 2021-11-06
    • 2010-10-29
    • 1970-01-01
    相关资源
    最近更新 更多