如何加快这个算法?

时间:2013-09-27 13:51:22

标签: c# .net plinq

这种计数方法在一次单元测试中非常慢。它可以通过并行化来改进吗?

编辑:要清楚,我无法更改日历界面或实现。我对计数算法感兴趣。

public static int CountBusinessDays(ICalendar calendar, DateTime start, DateTime end)
{
    int nBusinessDays = 0;

    for (DateTime current = start; current <= end; current = current.AddDays(1))
    {
        if (calendar.IsBusinessDay(current))
            ++nBusinessDays;
    }

    return nBusinessDays;
}

public interface ICalendar
{
    bool IsBusinessDay(DateTime day);
}

2 个答案:

答案 0 :(得分:2)

所以从这里开始是一个简单的辅助方法,从给定的点开始生成无限的天数序列:

public static IEnumerable<DateTime> Days(DateTime start)
{
    while (true)
    {
        yield return start;
        start = start.AddDays(1);
    }
}

然后我们可以使用TakeWhile生成代表您的范围的天数序列:

var allDays = Days(start).TakeWhile(day => day <= end);

接下来,我们可以使用PLINQ来平行每天的计算:

return allDays.AsParallel()
    .Where(day => calendar.IsBusinessDay(day))
    .Count();

请注意,计算给定日期是否为工作日可能不是特别耗时。如果是这种情况,则很可能管理所有不同线程的开销实际上比从并行化工作中获得的时间更长。底层集合的大小也很重要;如果时间越长,并行化的可能性就越大。您应该通过添加/删除AsParallel调用来运行一些测试以查看这是否真的是一个胜利。

答案 1 :(得分:0)

如果你无法改变实现,你唯一可能的加速方法是通过并行化(无论你是否通过应用程序代码处理多个线程)。

由于我们不知道calendar.IsBusinessDay()中发生了什么,我们无法告诉您它是否会更快。也许你有隐式序列化,也许你资源匮乏,也许它只是因为它不是线程安全而中断。如果你不知道答案,你可以想到4种选择。 1)尝试并行化,看它是否有效并且是因素。 2)修改或删除测试用例以使其更快。 3)向它投掷更多/更快的硬件,4)与它一起生活。