定时器的性能成本

时间:2011-07-25 07:20:42

标签: c# wpf performance timer

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

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

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

问题2:另一个解决方案是创建某种调度程序......一种“MultiTimer”,我可以在其中注册多个超时。有没有人建议如何实现这样的东西?

3 个答案:

答案 0 :(得分:2)

这可以使用Microsoft's Reactive Extensions以更优雅的方式实现 - 简称Rx。在其他很酷的功能中,Rx包含一个非常适合驯服激进事件源的节流方法。看看here

答案 1 :(得分:1)

如果您“create many thousand timers”,您将爆炸操作系统!定时器回调在不同的线程或线程池中运行,所以想象一下你创建了数千个线程......

但问题的解决方案取决于您首先从域层获取数据的方式。有关这方面的更多信息将有所帮助。

修改:您可以为更改的每个数据分配更新索引。如果您的数据经常在大约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);
}

编辑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:您可以尝试发布 - 订阅模型,它最适合您的业务场景。