【问题标题】:Improving The Performance Of My Application?提高我的应用程序的性能?
【发布时间】:2011-03-08 07:33:38
【问题描述】:

我有一个包含任务列表的数据库表。 我有一个程序可以计算指定时间段内每分钟运行的任务数。

我有一个查询可以获取指定时间段内的所有结果,还有一个循环中的 linq 查询可以获取每分钟间隔内的所有结果。

这一切都很好,但现在我很难提高代码的性能。

for(int i=0;i<oneMinuteIntervals;i++){
    var resultsThisMinute = 
    from fullResult //this contains all of the tasks in the whole period
    where //task is running during this one minute interval

    foreach(var result in resultsThisMinute){
        //Does stuff
    }
}

即使 resultsThisMinute 为空,foreach 循环也需要大约 33 毫秒。我尝试添加一个 if(resultsThisMinute.Count() == 0) 但这需要与 for 循环一样长的时间。有很多情况下在一分钟内有 0 个任务,所以我希望有一种更快的方法来检查这一点。

如果有,请留言,非常感谢!

【问题讨论】:

  • 与其使用 .Count() 迭代集合的内容,不如使用 .Any() 而不是。
  • Any 仍然会迭代到找到某些东西的地步。这可能是每次扫描的大部分集合。
  • 按时间四舍五入/下限到最接近的分钟分组怎么样?然后,您将只在行动所在的分钟内拥有组。
  • @spender,如果一项任务需要 5 分钟,则需要作为 5 个组的成员参与。这不是默认的分组行为。

标签: c# linq


【解决方案1】:

问题是您正在为每个循环迭代完全迭代 fullResult。这不是必需的。相反,您可以模拟一个时钟,并随着时间的推移查看哪些任务处于活动状态。

假设您的任务有一个 StartTime、一个 EndTime 和一个唯一的 Id...(未经测试)

Queue<Task> starts = new Queue(fullResult.OrderBy(task => task.StartTime));
Queue<Task> ends = new Queue(fullResult.OrderBy(task => task.EndTime));

Dictionary<int, Task> activeTasks = new Dictionary<int, Task>();

for(int i=0;i<oneMinuteIntervals;i++)
{ 
  DateTime current = ComputeDateTime(i);
    // may be needed
  // current = current.AddMinutes(1);

  while(starts.Any() && starts.Peek().StartTime < current)
  {
    Task startingTask = starts.Dequeue();
    activeTasks[startingTask.Id] = startingTask;
  }

  foreach(Task result in activeTasks.Values)
  {
    //Does stuff
  } 

  while(ends.Any() && ends.Peek().EndTime < current)
  {
    Task endingTask = ends.Dequeue();
    activeTasks[endingTask.Id] = null;
  }
}

另外 - 确保//Does Stuff 部分中没有发生数据访问。这会大大减慢你的速度。

对于数学倾向,我将原始的执行时间描述为 t * n + ?,这是简单的嵌套循环,其中 t 是分钟数,n 是 fullResult 中的行数和 ?是找到活动任务后枚举它们的执行时间。

我的代码是 2 * (n log n) + 2 * n + ? ,即两次排序和两次完整迭代。

【讨论】:

    【解决方案2】:

    除非您在 foreach 循环之前调用 .ToList() 或类似名称,否则您实际上并没有进行数据库查找,直到您开始枚举循环中的结果。这很可能是 33 毫秒的来源,如果是这个原因,它既无法避免也无需担心:数据库查询非常快。

    我假设你的循环中有一些东西会在每次迭代之间延迟一分钟,在这种情况下,没有必要避免每次迭代的查找开销。

    [编辑]

    刚刚注意到您正在从另一个查询中提取结果。您需要确保 fullResults 变量包含 ToList()ToArray() 的结果,以避免每次从数据库中提取结果时都访问数据库。

    【讨论】:

      【解决方案3】:

      您的查询正在对数据库进行 oneMinuteIntervals 调用。您可能可以按分钟分组并添加时间作为关键,以将其归结为单个数据库调用。所以你会有一个像

      这样的数据结构
      Dictionary<Datetime, fullResult>
      

      并使用单个数据库调用填充字典。

      【讨论】:

      • 任务运行五分钟会怎样?
      猜你喜欢
      • 1970-01-01
      • 2010-11-12
      • 2011-02-09
      • 1970-01-01
      • 1970-01-01
      • 2020-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多