Этот простой l oop требует много времени, и я не знаю почему - PullRequest
0 голосов
/ 28 мая 2020

У меня в приложении есть эта простая oop. Записи в IEnumerable rels - 468, записи в IEnumerable анализаторы - 78, поэтому каждый анализатор имеет 6 записей в rels

  IEnumerable<Reliability> rels = new Reliability().GetReliabilities()
    .Where(m => m.StartDate >= startDate && m.EndDate <= endDate && m.ContractId == ContractId && m.JobOrderId == JobOrderId && analyzers.Any(x => x.Id == m.AnalyzerId))
    .OrderBy(m => m.StartDate);

  List<ReliabilityModel> model = new List<ReliabilityModel>();

  foreach(Analyzer analyzer in analyzers)
  {
    long rel = rels.Where(m => m.AnalyzerId == analyzer.Id).Sum(m => m.ReliabilityHoursTicks);
    long tot = rels.Where(m => m.AnalyzerId == analyzer.Id).Sum(m => m.TotalHoursTicks);
    TimeSpan relHours = TimeSpan.FromTicks(rel);
    TimeSpan totHours = TimeSpan.FromTicks(tot);
    string relTime = ((int)Math.Truncate(relHours.TotalHours)).ToString() + ":" + relHours.Minutes.ToString("0#");
    string totTime = ((int)Math.Truncate(totHours.TotalHours)).ToString() + ":" + totHours.Minutes.ToString("0#");

    decimal value = Decimal.Divide(tot - rel, tot);

    model.Add(new ReliabilityModel
    {
      AnalyzerTagName = analyzer.TagName,
      AnalyzerTypeName = analyzer.AnalyzerTypeName, 
      ContractName = rels.Select(m => m.ContractName).FirstOrDefault(),
      JobOrderName = rels.Select(m => m.JobOrderName).FirstOrDefault(), 
      ReliabilityHours = relTime,
      TotalHours = totTime,
      Value = value.ToString("P4")
    });

  }

Проблема в том, что обработка занимает много времени, около 200 секунд, и я не понимаю, почему. Есть идеи?

Ответы [ 2 ]

1 голос
/ 28 мая 2020

Краткий ответ:

Проблема в

IEnumerable<Reliability> rels = new Reliability().GetReliabilities()...

без ToList () в конце.

Вы вызываете GetReliabilities() четыре раза на анализатор. Вероятно, GetReliabilities не просто возвращает список или что-то в этом роде, но на самом деле должен создать объект, содержащий все надежность.

Решение: добавьте .ToList (), прежде чем начинать его перечисление. Таким образом, надежность создается только один раз. последовательность, и пока у вас есть элемент, вы можете получить следующий, пока есть следующие элементы.

Имейте в виду, что перечисление IEnumerable<...> может занять некоторое время, особенно при создании перечисленных объекты занимают некоторое время.

Итак, сначала вы создаете IEnumerable. Этот IEnumerable еще не был перечислен.

IEnumerable<Reliability> rels = ...

Затем вы начинаете перечислять последовательность ваших анализаторов:

foreach(Analyzer analyzer in analyzers)
{
    long rel = rels.Where(m => m.AnalyzerId == analyzer.Id).Sum(m => m.ReliabilityHoursTicks);

Это означает, что для первого анализатора вы создаете все элементы, которые находятся в rels, и для каждого элемента вы решаете, хотите ли вы его сохранить. Из всех сохраненных элементов вы берете ReliabilityHoursTicks и суммируете их.

long tot = rels.Where(m => m.AnalyzerId == analyzer.Id).Sum(m => m.TotalHoursTicks);

Вы берете исходный запрос для rels, снова создаете все элементы, которые находятся в rels, и для каждого элемента ... (et c )

Позже:

  ContractName = rels.Select(m => m.ContractName).FirstOrDefault(),
  JobOrderName = rels.Select(m => m.JobOrderName).FirstOrDefault(), 

В зависимости от того, насколько умен GetReliabilities(), вы либо создаете один элемент rels, либо GetReliabilites выбирает все элементы, из которых вы используете только один

Итак, для каждого анализатора вы вызываете GetReliabilities четыре раза. Это ваше узкое место

1 голос
/ 28 мая 2020

Золотое правило производительности - измерять . Если вам нужно приблизить время, чтобы выяснить, в чем проблема, выберите более точное время. Либо путем установки дополнительных секундомеров, либо с помощью инструментов профилирования .

Некоторые возможные проблемы:

  1. rels можно лениво (дважды!) Оценивать для каждого итерация l oop. Используйте ToList, чтобы преобразовать его в реальный список. (как упоминалось несколькими людьми в комментариях)
  2. rels фильтруется анализатором на каждой итерации. Наверное, эффективнее было бы заранее сгруппировать надежности.

    relsByAnalyzer = rels.GroupBy (r => r.AnalyzerId) .ToDictionary (r => r.Key, r => r.ToList ());

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...