65.9K
CodeProject 正在变化。 阅读更多。
Home

提高 WPF Dispatcher 的性能

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.67/5 (3投票s)

2009年3月15日

CPOL

2分钟阅读

viewsIcon

34107

downloadIcon

299

如何提高使用 WPF Dispatcher 时的性能

引言

我的小列表是对 ObservableCollection<T> 的改进,用于处理多线程。并且(关键在于)只在主线程中执行事件处理程序。这为我带来了巨大的性能提升。

背景

我最初的方法是为我的集合提供一个 Dispatcher 来调用 CollectionChanged 事件。但这导致了一些性能问题,因为我在自己的处理程序中进行了一些搜索。使用新的列表,只有 WPF 处理程序在主线程中执行,这当然更快。

Using the Code

您可以像使用普通的 Observed Collection 一样使用我的集合。我仍然存在一些同步问题,因为 Microsoft 没有使用线程安全的枚举。如果有人知道如何改进这一点,请告诉我。

这是集合的关键部分

//Override the event to be able to get the invocation list
public override event NotifyCollectionChangedEventHandler CollectionChanged;

protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
    if (CollectionChanged != null)
    {
        //get all Delegates
        foreach (Delegate del in CollectionChanged.GetInvocationList())
        {
            // look for a Dispatcher
            PropertyInfo prop = del.Target.GetType().GetProperty("Dispatcher");
            if (prop != null)
            {
                //Foreground Thread Invoke
                (prop.GetValue(del.Target, null) 
                      as Dispatcher).BeginInvoke(del, this, e);
            }
            else
            {   
                //Linear Invoke not in Foreground thread
                del.DynamicInvoke(this, e);
            }
        }
    }
}

高级线程安全

由于 Microsoft 不关心检查 CollectionChangedEvents,我需要自己来完成。这将在我跟踪发布到 WPF Dispatcher 的操作之前发生

  1. 锁定列表(这会阻止 Dispatcher 处理您发布的事件)
  2. 添加一个项目
  3. 再次删除该项目
  4. 释放列表上的锁(Dispatcher 现在可以更新)
  5. Dispatcher 尝试访问步骤 2 中的索引 1 处的元素,并崩溃,因为此时该项目不在列表中

我修改了集合的 OnCollectionChanged 来跟踪从 DispatcherInstance.BeginInvoke 获取的操作。因此,在每个事件上,我首先检查之前的操作,如果它们干扰了当前的操作。当一个操作完成时,我将其从跟踪中删除。目前这还不是完全可用的,所以如果您尝试我的集合,请告诉我如何改进处理方式。现在就是这样

  1. 锁定列表
  2. 添加一个项目
  3. 再次删除该项目
  4. 检测步骤 2 和 3 中的操作相互抵消并取消两者
  5. 释放锁
  6. Dispatcher 没问题

历史

  • 2009 年 3 月 15 日:初始版本
  • 2009 年 3 月 19 日:添加了线程安全扩展
© . All rights reserved.