2013-09-27 5 views
0

Этот метод подсчета довольно медленный в одном модульном тесте. Можно ли улучшить, возможно, путем параллелизации?Как ускорить этот алгоритм?

Редактировать: Чтобы быть ясным, я не могу изменить интерфейс календаря или реализации. Меня интересует алгоритм подсчета.

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); 
} 
+0

У вас есть доступ к реализации 'ICalendar'? Или вы можете изменить интерфейс так, чтобы у вас был метод, который дает вам количество рабочих дней? Я думаю, было бы проще реализовать это в контексте «ICalendar», так как у вас должно быть достаточно информации, чтобы просто вычислить это без итерации. – ppetrov

+1

Это невозможно для нас ответить. Вы попробовали? Начните с выяснения, почему это так медленно. Может ли 'IsBusinessDay' вызывать базу данных? И парализовать операцию и измерить, если это поможет. – Steven

+0

Какова реализация IsBusinessDay примерно? Если он делает вызов веб-службы для каждого дня, то самые большие улучшения скорости будут достигнуты за счет загрузки списка рабочих дней навалом. – dtb

ответ

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.

+0

Спасибо, это ускорило медленный модульный тест от ~ 450 мс до ~ 300 мс –

0

Если вы не можете изменить реализацию, только ваши возможные средства ускорения вещей вверх осуществляется с помощью распараллеливания (или нет ваша ручка ваши несколько потоков с помощью кода приложения).

Поскольку мы не знаем, что происходит в календаре.IsBusinessDay(), мы не можем сказать вам, будет ли это быстрее. Возможно, у вас есть неявная сериализация, может быть, вы голоден от ресурсов, может быть, она просто ломается, потому что она не является потокобезопасной. Если вы не знаете ответа, у вас есть 4 варианта, о которых я могу думать. 1) Попробуйте распараллеливать и посмотрите, работает ли он и является фактором. 2) Измените или устраните тестовый пример, чтобы сделать его быстрее. 3) Бросьте на него все больше/быстрее, 4) Живи с ним.

Смежные вопросы