计时器的性能成本

本文关键字:性能 计时器 | 更新日期: 2023-09-27 18:03:15

我需要优化一个相当大的WPF应用程序。我们以非常高的频率从域层获得数据更新。优化UI的一个想法是延迟一些UI元素的更新,以提高UI性能。假设我们在域模型中有一个属性"Counter",它每秒变化大约100次。因此,我们可以创建一个每秒只触发一次的计时器,并在计时器触发时更新ViewModel中的相应属性。到目前为止效果还不错。计时器会每秒将值从域对象复制一次到视图模型,我们就完成了。

问题是:每个视图模型实例代表列表中的一个条目。这个列表可能有几千个条目。根据我所描述的解决方案,我们还需要创建数千个计时器。我想创建这么多计时器实例并不是一个好主意。一个简单的解决方案是在基类或其他地方创建一个静态计时器实例,并使用这个实例更新所有视图模型。但这也是不可能的。我们有任何不同的属性,应该独立于领域模型进行更新,并且每个属性都应该有一个单独的更新速率。

问题1:有人知道计时器有多贵吗?如果我创建数千个计时器真的重要吗?

问题2:另一个解决方案是创建某种调度程序…一种"多计时器",我可以注册多个超时。有人对如何实现这样的东西有什么建议吗?

计时器的性能成本

这可以用一种更优雅的方式实现,使用微软的响应式扩展——简称Rx。在其他很酷的功能中,Rx包含一个Throttle Method,它非常适合驯服激进的事件源。

如果你" create many thousand timers "你会炸了操作系统!计时器回调在不同的线程或线程池中运行,所以想象一下您正在创建1000个线程…

然而,问题的解决方案取决于您如何从域层获取数据。更多的信息会有帮助的。

Edit:您可以为每个更改的数据分配更新索引。如果你的数据在100ms中频繁更新,你希望每一行只在1 second之后更新,那么使用DictionaryConcurrentDictionary来保存每个数据及其更新索引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);
}

Edit2:您在注释中声明:

我不能保证域对象值是不断更新的。它可能在一秒钟内改变一个属性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);
}

Question1:计时器始终是现有应用程序的开销。它消耗了性能,特别是您的情况下有数千个计时器。

问题2:您可以尝试发布-订阅模式,它最适合您的业务场景。