我有一个包含任务列表的数据库表。 我有一个程序可以计算在指定时间段内每分钟运行的任务数。
我有一个查询可以获取指定时间段内的所有结果,另一个查询在一个循环中查找每一分钟间隔内的所有结果。
这一切都很好,但现在我在提高代码性能方面遇到了困难。
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个任务,所以我希望有更快的方法来检查这一点。
如果有,请发帖,我真的很感激!
答案 0 :(得分:2)
问题是你是为每个循环迭代完全迭代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中的rowcount和?是在找到活动任务后枚举活动任务的执行时间。
我的代码是2 *(n log n)+ 2 * n +? ,这是两种和两次完整的迭代。
答案 1 :(得分:1)
除非你在foreach循环之前调用.ToList()
或类似的东西,否则在开始枚举循环中的结果之前,你实际上并没有进行数据库查找。这可能是33毫秒的来源,如果这是原因,它既不可避免也不值得担心:数据库查询非常快。
我假设你的循环中有一些东西在每次迭代之间延迟一分钟,在这种情况下,没有必要避免每次迭代开销的查找。
[编辑]
刚刚注意到你正在从另一个查询中提取结果。您需要确保fullResults
变量包含ToList()
或ToArray()
的结果,以避免每次从中提取结果时都会访问数据库。
答案 2 :(得分:0)
您的查询正在对数据库进行oneMinuteIntervals调用。您可以按分钟分组,并将时间添加为关键,以便将其转换为单个数据库调用。所以你会有一个像
这样的数据结构Dictionary<Datetime, fullResult>
使用单个数据库调用填充字典。