首页 > 解决方案 > 比较数据的最有效方法

问题描述

在我们的应用程序中,有一个周期性调用的函数,需要将之前的调用结果与当前调用结果进行比较,如下所示

public class Record
{
  public long Id{get;set}
  public bool SwitchStatus{get;set;}

//.....Other Fields.....
}

public class Consumer
{
  private List<Tuple<long, bool>> _sortedRecordIdAndStatus = new List<Tuple<long, bool>>();

 void IGetCalledEveryThreeSeconds(List<Record> records)
 {

    var currentsortedRecordIdAndStatus = records.Select(x=> new Tuple<long, bool> (x.Id, x.SwitchStatus)).ToList();
   if(!currentsortedRecordIdAndStatus.SequenceEqual(_sortedRecordIdAndStatus))
   {
      DoSomething();
   }

  _sortedRecordIdAndStatus  = currentsortedRecordIdAndStatus;

 }

}

ToList() 函数在调用数千条记录时会花费大量时间。这就是目前的瓶颈。

我正在尝试优化这个程序。我只需要比较一个数据块是否相同

我想我只需要从传入记录中创建一个数据块,并将该块与创建的下一个调用块进行比较,依此类推......我只需要知道该块是否相同(包括顺序)。我什至不需要查看里面的数据

例如。对于块的内容

[[1000][true]]
[[2000][false]]
[[1500][true]]

有什么办法可以优化我的代码吗?

标签: c#

解决方案


这附带了一个标准警告,即过早的优化是万恶之源,我相信你的说法,这确实是你的应用程序性能的瓶颈。

  1. 如果记录块的长度可能不同,那么检查它们的长度要比遍历它们快得多。
  2. 如果您可以使用流式 LINQ 运算符,则可以在您发现两个块不相同时进行短路。如果经常出现它们不一样的情况,那可以带来相当大的性能提升。
  3. 如果它不是太多的内存开销,并且如果您可以安全地假设代码的其他部分在传递给您的方法后不会更改 List,那么您应该考虑只保留给您的 List而不是创造一个新的。

像这样的东西:

public class Consumer
{
 private List<Record> _previousRecords = new List<Record>();

 void IGetCalledEveryThreeSeconds(List<Record> records)
 {
    if(records.Count == _previousRecords.Count
       && records.Select(x => (x.Id, x.SwitchStatus)).SequenceEqual(
          _previousRecords.Select(x => x.Id, x.SwitchStatus))
    {
      DoSomething();
    }

    _previousRecords  = records;
 }

但是,考虑到您对输入通常相同的评论,我不知道这些优化是否会有益。由于您几乎必须遍历整个列表以验证它们是否不同,无论如何,这些优化不会将事情改善一个数量级。并且很难知道避免每次创建新 List 是否会抵消每次从 _previousRecords 中选择新元组的开销。

如果您确实需要从中挤出每一盎司的性能,并且您肯定这是瓶颈,并且您无法提出一个更广泛的架构解决方案来避免这个瓶颈,那么您最后的最佳选择是可能是为了避免 LINQ 并使用for循环。但这些改进可能不足以产生业务层面的差异。

public class Consumer
{
 private List<Record> _previousRecords = new List<Record>();

 void IGetCalledEveryThreeSeconds(List<Record> records)
 {
    var length = records.Count;
    if(length != _previousRecords.Count)
    {
      return;
    }

    for(int i = 0; i < length; i++)
    {
        var record1 = records[i];
        var record2 = _previousRecords[i];
        if(record1.Id != record2.Id || record1.SwitchStatus != record2.SwitchStatus)
        {
          _previousRecords = records;
          return;
        }
    }

    DoSomething();
 }

推荐阅读