我需要优化一个相当大的WPF应用程序。我们正在以非常高的频率从域层获取数据更新。优化UI的一个想法是延迟一些UI元素的更新以改善UI性能。假设我们在域模型中有一个属性“Counter”,每秒更改大约100次。因此,我们可以创建一个仅每秒触发一次的计时器,并在计时器触发时更新ViewModel中的相应属性。到目前为止,这非常好。计时器只会将域对象中的值复制一次到视图模型,我们就完成了。
问题是:每个视图模型实例表示列表中的条目。这个列表可能有几千个条目。通过我描述的解决方案,我们还将创建数千个计时器。我猜想创建这么多的计时器实例并不是一个好主意。一个简单的解决方案是在基类或其他地方创建静态计时器实例,并使用此单个实例更新所有视图模型。但这也是不可能的。我们有任何不同的属性应该独立于域模型进行更新,并且每个属性都应该具有单独的更新速率。
问题1:有没有人知道计时器有多贵?如果我要制作数千个计时器真的很重要吗?
问题2:另一个解决方案是创建某种调度程序......一种“MultiTimer”,我可以在其中注册多个超时。有没有人建议如何实现这样的东西?
答案 0 :(得分:2)
这可以使用Microsoft's Reactive Extensions以更优雅的方式实现 - 简称Rx。在其他很酷的功能中,Rx包含一个非常适合驯服激进事件源的节流方法。看看here。
答案 1 :(得分:1)
如果您“create many thousand timers
”,您将爆炸操作系统!定时器回调在不同的线程或线程池中运行,所以想象一下你创建了数千个线程......
但问题的解决方案取决于您首先从域层获取数据的方式。有关这方面的更多信息将有所帮助。
修改:您可以为更改的每个数据分配更新索引。如果您的数据经常在大约100ms
中更新,并且您希望每行仅在1 second
后更新,那么请使用保存每个数据及其更新的Dictionary
或ConcurrentDictionary
索引int
“或者如果不是DataTime
中的所有数据更新,则可以使用100ms
:”
private ConcurrentDictionary<Data, int> _dataUpdateFrequence = new ConcurrentDictionary<Data, int>();
private const int MaxFrequent = 10;
Data data = null;
private void OnDataUpdated(Data data)
{
int lastUpdateIndex = _dataUpdateFrequence.GetOrAdd(data, 0);
int newUpdateIndex = (lastUpdateIndex + 1) % MaxFrequent;
bool needsUpdate = lastUpdateIndex == 0 || newUpdateIndex == 0;
if (needsUpdate)
{
//Update the UI.
}
_dataUpdateFrequence.TryUpdate(data, newUpdateIndex , lastUpdateIndex);
}
编辑2:您在评论中说:
我无法保证域对象值不断更新。它可能会在一秒钟内更改一次属性100次,然后再也不会再次
在这种情况下,我会使用DateTime
而不是int
,因此检查上次更新是否大于1秒然后更新UI,否则忽略。但是在这里你还需要定义一个计时器,它将更新每个30 second
中的所有字段。所以没有饥饿你的任何更新“以防万一,例如某些字段会在半秒内更新,而且永远不会再次更新!”所以:
private const int UpdateAllInterval = 30 * 1000;//30 seconds
private readonly TimeSpan MinimumIntervalToUpdate = new TimeSpan(0, 0, 1);
private ConcurrentDictionary<Data, DateTime> _dataUpdateFrequence = new ConcurrentDictionary<Data, DateTime>();
private System.Timers.Timer _updateTimer = new System.Timers.Timer();
//At the UI Constructor:
public Window..
{
_updateTimer.Interval = UpdateAllInterval;
_updateTimer.AutoReset = true;
_updateTimer.Elapsed += OnUpdateTimerElapced;
_updateTimer.Start();
}
private void OnUpdateTimerElapced(object sender, System.Timers.ElapsedEventArgs e)
{
this.Dispatcher.Invoke(/*update the UI method*/);//or this.Invoke if winforms
}
private void OnDataUpdated(Data data)
{
DateTime currentTime = DateTime.Now;
DateTime lastUpdateTime = _dataUpdateFrequence.GetOrAdd(data, currentTime);
bool needsUpdate = lastUpdateTime == currentTime ||
currentTime > lastUpdateTime.Add(MinimumIntervalToUpdate);
if (needsUpdate)
{
//Update the UI.
}
_dataUpdateFrequence.TryUpdate(data, currentTime, lastUpdateTime);
}
答案 2 :(得分:0)
问题1:计时器始终是现有应用程序的开销。它会降低性能,特别是对于有数千个定时器的情况。
问题2:您可以尝试发布 - 订阅模型,它最适合您的业务场景。