提高 WPF Dispatcher 的性能
如何提高使用 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 的操作之前发生
- 锁定列表(这会阻止 Dispatcher 处理您发布的事件)
- 添加一个项目
- 再次删除该项目
- 释放列表上的锁(Dispatcher 现在可以更新)
- Dispatcher 尝试访问步骤 2 中的索引 1 处的元素,并崩溃,因为此时该项目不在列表中
我修改了集合的 OnCollectionChanged
来跟踪从 DispatcherInstance.BeginInvoke
获取的操作。因此,在每个事件上,我首先检查之前的操作,如果它们干扰了当前的操作。当一个操作完成时,我将其从跟踪中删除。目前这还不是完全可用的,所以如果您尝试我的集合,请告诉我如何改进处理方式。现在就是这样
- 锁定列表
- 添加一个项目
- 再次删除该项目
- 检测步骤 2 和 3 中的操作相互抵消并取消两者
- 释放锁
- Dispatcher 没问题
历史
- 2009 年 3 月 15 日:初始版本
- 2009 年 3 月 19 日:添加了线程安全扩展