Почему скорость Java-процесса внутри нескольких циклов замедляется по мере его выполнения?

#java #performance #loops

#java #Производительность #циклы

Вопрос:

Я использую Win 7, Java 8 на многоядерной рабочей станции Intel. У меня есть что-то вроде этого :

   int SampleWeeksArray[]=new int[]{23,25,33},IdArray[]=new int[]{0,1,2};

  for (int StartDay=25;StartDay<36;StartDay  )
    for (int SampleWeeks : SampleWeeksArray)
      for (int Id : IdArray)
        for (float ValueFactor=0.08f;ValueFactor<0.13f;ValueFactor =0.01)
        {
          DataDigester dataDigester=new DataDigester();
          dataDigester.StartDay=StartDay;
          dataDigester.SampleWeeks=SampleWeeks;
          dataDigester.Id=Id;
          dataDigester.ValueFactor=ValueFactor;
          dataDigester.DoRun();
        }
  

Внутри dataDigester.DoRun() считывает некоторые текстовые файлы данных, анализирует каждую строку и выполняет некоторую статистику с массивами, векторами и хэш-картами, а также использует ThreadPoolExecutor для запуска нескольких процессов, а затем сохраняет результаты в файл.

Странно то, что каждый отдельный запуск DoRun() занимает всего 10 минут, но внутри циклов он начинается с 10 минут. но постепенно замедляется до 20, 30 мин. для каждого DoRun() .

Если я остановлю цикл, когда он займет 30 минут, а затем начну с того места, где я остановился, это снова займет 10 минут. и в конечном итоге замедляется до 20, 30 мин. снова. Почему?

Я даже вставил следующие строки после DoRun() , но это не улучшило скорость, все еще замедляется :

    Thread.sleep(20*1000);                     // Rest for 20 seconds
   System.gc();
  

Внутри каждого цикла DataDigester dataDigester=new DataDigester() создает новый объект, он должен быть переработан после DoRun(), почему он замедлился?

Я также заметил из диспетчера задач Windows, что использование памяти увеличивается по мере продолжения циклов. Кажется, Java каким-то образом обременяет себя чем-то и замедляется, поэтому в этом случае, как поддерживать скорость на постоянном уровне 10 мин. для каждого запуска в циклах?

Комментарии:

1. Может ли со временем появляться больше данных?

2. Не используйте double или float для итераторов. Это связано с тем, что плавающие типы неточны, и вы можете получить неожиданный результат. Также попробуйте использовать соглашения о коде Java, где переменные начинаются со строчных букв. например for (int v = 8; v <= 13; v ) float valueFactor = v / 100.0f;

Ответ №1:

Трудно сказать, не зная, что такое DataDigester и что он делает, но я могу назвать несколько возможных причин:

  1. если DataDigester.DoRun запускает новый поток — затем, по мере увеличения количества потоков, время, доступное для каждого потока, уменьшается. Если он использует аппаратные потоки, то время значительно увеличится, как только вы перейдете от 1 к 2 потокам на аппаратный поток.

  2. DataDigester может иметь статическую структуру, к которой он добавляется, и которая становится все медленнее и медленнее, чем больше вы добавляете в нее

Комментарии:

1. Это то, что я подозревал, я изучу их, спасибо.

Ответ №2:

Объявите только один DataDigester и повторно используйте его для всех ваших циклов вместо создания тысяч и тысяч из них.

 int SampleWeeksArray[]=new int[]{23,25,33},IdArray[]=new int[]{0,1,2};

DataDigester dataDigester;
for (int StartDay=25;StartDay<36;StartDay  )
    for (int SampleWeeks : SampleWeeksArray)
        for (int Id : IdArray)
            for (float ValueFactor=0.08f;ValueFactor<0.13f;ValueFactor =0.01)
            {
                dataDigester=new DataDigester();
                dataDigester.StartDay=StartDay;
                dataDigester.SampleWeeks=SampleWeeks;
                dataDigester.Id=Id;
                dataDigester.ValueFactor=ValueFactor;
                dataDigester.DoRun();
            }
        }
    }
}
  

Это должно помочь с вашими проблемами сборки мусора, а также со сроками.

Комментарии:

1. Это было похоже на то, что вы предложили в начале, но я заметил замедление, поэтому я переместил DataDigester dataDigester; внутри циклов, я полагаю, он должен перерабатываться после каждого цикла и, следовательно, с постоянной скоростью. Но это не так.

2. Вы должны смотреть на то, что происходит внутри DataDigester для повышения производительности. И если DD.DoRun() запускает поток, возможно, при ограничении пула потоков, вы можете слишком часто менять потоки и довольно быстро увеличивать нагрузку на процессор.