C# 定时器的性能成本

C# 定时器的性能成本,c#,wpf,performance,timer,C#,Wpf,Performance,Timer,我需要优化一个相当大的WPF应用程序。我们正在以非常高的频率从域层获得数据更新。优化UI的一个想法是延迟一些UI元素的更新以提高UI性能。假设我们在域模型中有一个每秒改变100次的属性计数器。因此,我们可以创建一个每秒只触发一次的计时器,并在计时器触发时更新ViewModel中的相应属性。到目前为止效果还不错。计时器只需每秒将值从域对象复制到视图模型一次,我们就完成了 问题是:每个视图模型实例都表示列表中的一个条目。这个列表可能有几千个条目。使用我描述的解决方案,我们还将创建数千个计时器。我猜创

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

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

问题1:有人知道计时器有多贵吗?如果我能创造上千个计时器,这真的重要吗


问题2:另一个解决方案是创建某种调度程序。。。一种可以记录多次超时的多定时器。有人对如何实现这样的功能有什么建议吗?

这可以通过使用Rx以更优雅的方式实现。在其他酷功能中,Rx包含一种节流方法,非常适合驯服攻击性事件源。看一看。

这可以通过使用简单的Rx以更优雅的方式实现。在其他酷功能中,Rx包含一种节流方法,非常适合驯服攻击性事件源。看一看。

如果你创建了数千个计时器,你会毁掉操作系统!。计时器回调在不同的线程或线程池中运行,因此假设您正在创建一千个线程

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

编辑:您可以为更改的每个数据分配更新索引。如果您的数据在大约100ms内频繁更新,并且您希望每行仅在1秒后更新,则使用保存每个数据及其更新索引int的字典或ConcurrentDictionary,或者如果不是所有数据在100ms内更新,则可以使用DataTime

如果你创建了数千个计时器,那么你将破坏操作系统!。计时器回调在不同的线程或线程池中运行,因此假设您正在创建一千个线程

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

编辑:您可以为更改的每个数据分配更新索引。如果您的数据在大约100ms内频繁更新,并且您希望每行仅在1秒后更新,则使用保存每个数据及其更新索引int的字典或ConcurrentDictionary,或者如果不是所有数据在100ms内更新,则可以使用DataTime


问题1:对于现有应用程序,计时器始终是开销。它会消耗性能,尤其是你的数千定时器


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

问题1:对于现有应用程序,计时器始终是开销。它会消耗性能,尤其是你的数千定时器


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

我很乐意使用它。。。但决定不使用Rx。很不幸,这不是一个选项。反对RX的原因是什么?因为它不是.Net的官方部分,也没有可用的源代码。所以我们的决定是不应该使用is,因为我们没有办法修复官方的.Net文件中没有的可能的bug。。。但无论如何,我很想用这个。。。但决定不使用Rx。很不幸,这不是一个选项。反对RX的原因是什么?因为它不是.Net的官方部分,也没有可用的源代码。所以我们的决定是不应该使用is,因为我们没有办法修复官方的.Net文件中没有的可能的bug。。。但无论如何,有人特别提到数据更改太频繁,发布-订阅模型无法正常工作。有人特别提到数据更改太频繁,发布-订阅模型无法正常工作。域模型对象正在实现INotifyPropertyChanged接口,并且正在引发PropertyChanged eve
当域数据更改时使用nt。我们或多或少地将每个域对象实例包装到一个视图模型实例中。某些域模型属性仅映射到视图模型属性,而某些属性在更改时从域模型数据计算。这回答了你的问题吗?很好。。。但是:如果我正确理解了你的解决方案,它依赖于不断的更新。我不能那样做。我必须确保数据被刷新,即使没有从域对象进行进一步更新。您的解决方案将忽略更新,直到再次达到计数。但我不能保证域对象值是不断更新的。它可能会在一秒钟内更改属性100次,然后再也不会更改。因此,在这种情况下,我最终会得到一个旧值,该值永远不会刷新到正确的值。@hari:那么,如果服务器上的时间不经常更改的话。然后使用DateTime而不是int,以便在上次更新数据时_dataUpdateFrequence.TryUpdatedata,DateTime.Now,previousTime;,因此,检查上次更新是否为timespan大于1秒,然后更新UI,否则忽略。但在这里,您还需要定义一个计时器,例如每30秒更新一次所有字段。因此,如果某个字段只更新了一些更新,那么就不会对您的任何更新感到饥饿…@hari:answer updated添加代码来描述datetime的概念非常感谢您的回答。那就行了。但说实话,我不太喜欢这个解决方案,因为它太复杂了。我不想要一个额外的计时器,在没有更新时触发更新。这感觉就像是一个解决办法。我要做的是创建一个字典,将更新间隔映射到更新程序对象。应用程序中的大多数对象的更新速度都是200毫秒或500毫秒,所以我这里只有两个条目。每个更新程序对象将维护一个应更新的对象队列,并在计时器间隔内处理此队列。域模型对象正在实现INotifyPropertyChanged接口,并且在域数据更改时仅引发PropertyChanged事件。我们或多或少地将每个域对象实例包装到一个视图模型实例中。某些域模型属性仅映射到视图模型属性,而某些属性在更改时从域模型数据计算。这回答了你的问题吗?很好。。。但是:如果我正确理解了你的解决方案,它依赖于不断的更新。我不能那样做。我必须确保数据被刷新,即使没有从域对象进行进一步更新。您的解决方案将忽略更新,直到再次达到计数。但我不能保证域对象值是不断更新的。它可能会在一秒钟内更改属性100次,然后再也不会更改。因此,在这种情况下,我最终会得到一个旧值,该值永远不会刷新到正确的值。@hari:那么,如果服务器上的时间不经常更改的话。然后使用DateTime而不是int,以便在上次更新数据时_dataUpdateFrequence.TryUpdatedata,DateTime.Now,previousTime;,因此,检查上次更新是否为timespan大于1秒,然后更新UI,否则忽略。但在这里,您还需要定义一个计时器,例如每30秒更新一次所有字段。因此,如果某个字段只更新了一些更新,那么就不会对您的任何更新感到饥饿…@hari:answer updated添加代码来描述datetime的概念非常感谢您的回答。那就行了。但说实话,我不太喜欢这个解决方案,因为它太复杂了。我不想要一个额外的计时器,在没有更新时触发更新。这感觉就像是一个解决办法。我要做的是创建一个字典,将更新间隔映射到更新程序对象。应用程序中的大多数对象的更新速度都是200毫秒或500毫秒,所以我这里只有两个条目。每个updater对象将维护一个应该更新的对象队列,并在计时器间隔内处理该队列。我确实有很多对象需要延迟刷新。但我可能没有那么多不同的刷新时间。所以我可以创建一个包含更新程序的字典,每个更新程序代表一个唯一的更新频率。每个更新程序都有一个计时器和一个队列,我可以在其中安排更新。这样,我只有几个计时器为我的数千个对象服务。完成后我会发布一个代码剪贴。谢谢贾拉尔的回答为我指出了一个可能的解决办法。我确实有很多对象需要延迟刷新。但我可能没有那么多不同的刷新时间。所以我可以创建一个包含更新程序的字典,每个更新程序代表一个唯一的更新频率。每个更新程序都有一个计时器和一个队列,我可以在其中安排更新。这样,我只有几个计时器为我的数千个对象服务。完成后我会发布一个代码剪贴。T 汉克斯!
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);
}
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);
}