2

对于这个问题,我有一个特定的场景,但是一个好的通用解决方案应该适用于许多情况:

我有一个 WPF ItemsControl,其项目的 IsSelected 属性是绑定到视图模型中相应属性的数据。然后,我有一个计算密集型例程,该例程(在后台线程上)在所选项目上运行。问题是,如果我在更改项目的 IsSelected 属性时触发计算密集型任务,那么当同时选择多个项目时,计算密集型任务会在每个选定的项目运行一次,而不是在所有选择后仅运行一次项目已被选择,这就是它需要做的所有事情,因此它最终占用的处理器时间比真正需要的要多得多。

IEnumerable<MyObject> items;

...

void IsSelectedPropertyChangedListener(object sender, PropertyChangedEventArgs e)
{
    if(e.PropertyName == "IsSelected")
        DoSomeIntensiveCalculation(items.Where(t=>t.IsSelected));
}

void DoSomeIntensiveCalculation(IEnumerable<MyObject> itemsToCalculate)
{
    ...
}

当然,我可以只注册 ItemsControl 的 SelectionChanged 事件并触发它,因为即使选择了多个项目,每次选择更改也只会调用一次,但这有点违反 MVVM,还有其他情况是通用解决方案可以适用于,这不会有这么容易的工作。(如果你有充分的理由说明为什么在这种特殊情况下我应该这样做,因为它比任何替代方案都好,我愿意听)

我能想到的另一个例子可能是你有一个 ObservableCollection,你想在每次它改变时计算一些困难的东西。当然,您会注册 CollectionChanged 事件来触发您的计算,但假设某事正在一次将大量项目添加到集合中,您实际上只需要在所有项目都添加后进行一次计算,这样做是为了添加的每个项目都会大大降低性能。

如果另一个实例已经开始运行,我可以阻止密集任务运行,只需设置一个标志让它在它完成时再运行一次,这将导致它只运行两次,即使一次选择了一堆东西,但这仍然比实际需要的多一倍。

每次启动一个新任务时,我都可以杀死已经运行的任务实例,但这需要向计算任务添加大量代码,以便在请求时优雅地停止自身。它也不适用于我无法控制密集任务的情况(即它在第三方库中并且没有提供优雅的停止机制)。

4

1 回答 1

0

Not 100% sure what you are asking but here are some ideas:

  1. Use Task Parallel Library. The Task mananager will decide whether or not to launch a thread.
  2. Use a blocking queue .
  3. Redesign the interface to have a compute button
  4. Cache the result after the first computation.
于 2013-09-18T14:09:20.247 回答