Почему детерминированный алгоритм в Java выполняется в разное время?

У меня есть программа на Java, которая вычисляет проблему с n телами. На каждой итерации он проверяет силы, которые каждое тело прилагает к каждому другому телу, а затем перемещает их в соответствии с этими силами.

Тела всегда начинаются в одном и том же месте (у меня они расположены по кругу, от тела 0 до тела n), они всегда проверяются и перемещаются в одном и том же порядке (от тела 0 до n). Однако, когда я запускаю программу 30 раз, у меня резко различается время работы. Одно время работы составит 2 947 188 миллисекунд (49 минут), а другое - 920 967 миллисекунд (15 минут). Я не удивлен порядком этих времен, потому что я использую метод грубой силы (O (n ^ 2)) на МНОГО телах. Но мне интересно, почему у детерминированного алгоритма такая дисперсия? если один и тот же алгоритм раз за разом, не должно ли время работы быть таким же (или, по крайней мере, близким)?

Прежде чем вы спросите, да, я измеряю время потока, который выполняет вычисления, а не время настенных часов.

Изменить. Я измеряю время так:

ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long startUserTimeNano = bean.getCurrentThreadCpuTime();

// ... Code to do the stuff...

double taskUserTimeNano = (bean.getCurrentThreadCpuTime() - startUserTimeNano);
CPUmillisecondsElapsed += taskUserTimeNano/1000000.0;

Измеряет ли это что-нибудь, кроме шага расчета?

Второе изменение - теперь я изменил его, чтобы измерять время следующим образом:

ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long startUserTimeNano = bean.getCurrentThreadUserTime();

// ... Code to do the stuff...

double taskUserTimeNano = (bean.getCurrentThreadUserTime() - startUserTimeNano);
CPUmillisecondsElapsed += taskUserTimeNano/1000000.0;

Однако результаты по-прежнему нельзя повторить. Я также попытался запустить свою программу с флагом -Xint, и результаты ВСЕ ЕЩЕ не повторялись.

Можно ли предположить, что проблема заключается в алгоритме и многопоточности? Или это все еще проблема, связанная с Java?


person WhiteTiger    schedule 01.04.2011    source источник
comment
Меняются ли как-то условия, в которых вы работаете?   -  person ldog    schedule 01.04.2011
comment
Попробуйте пробную копию JProfiler? ej-technologies.com/products/jprofiler/overview.html - можно было подключиться к своей проге. Сохраняйте снимки запусков, смотрите на память, использование процессора и т. Д. Возможно, ваша проблема связана с памятью и сборкой мусора.   -  person David Victor    schedule 01.04.2011
comment
Вы говорите, что рассчитываете только один поток. Есть ли другие темы?   -  person MAK    schedule 01.04.2011


Ответы (3)


Вы уверены, что правильно измеряете время? Внутри jvm может быть много потоков, которые невидимы для вас как пользователя. Если вы получаете системное время, вы игнорируете существование этих потоков. Кроме того, если вы запускаете какие-либо другие потоки, вы можете игнорировать время, которое они добавляют.

person mrK    schedule 01.04.2011

Тестирование многопоточных программ может быть сложной задачей из-за динамической компиляции, сборки мусора и адаптивной оптимизации. Я предлагаю прочитать главу 12 книги Брайана Гетца «Параллелизм в Java на практике».

person Steve Emmerson    schedule 01.04.2011
comment
Отличная книга по параллелизму в Java! - person J T; 02.04.2011
comment
Да, если он работает на виртуальной машине HotSpot, я бы сказал, что это вызвано компилятором. Некоторое время назад я ответил на похожий вопрос: stackoverflow.com/questions/3703644/ - person gpeche; 02.04.2011

Предполагая, что поток, который вы синхронизируете, является лишь одним из многих потоков, простое получение разницы времени начала и окончания вычислений в потоке на самом деле не измеряет фактическое время процессора, затрачиваемое потоком. Он конкурирует с другими потоками и должен будет приостанавливаться / ждать, пока выполняются другие потоки, но вы также будете считать время ожидания.

Поскольку способ планирования потоков может различаться, и мы также должны учитывать сборку мусора, общее время, затрачиваемое на выполнение потока от начала до конца, может сильно различаться. Но фактическое количество необходимого процессорного времени не изменится.

Изменить:

Я думаю, что вам нужно измерить количество времени, которое поток провел в пользовательском режиме. Это должно избавить от времени, затрачиваемого на ожидание ОС / JVM, и измерить только время, потраченное на выполнение в потоке. Итак, попробуйте использовать getCurrentThreadUserTime.

Я нашел более раннюю ветку SO об этом: Разница между временем пользователя потока и временем процессора потока в Java

person MAK    schedule 01.04.2011
comment
Итак, как мне измерить время строго потока, выполняющего вычисления? - person WhiteTiger; 01.04.2011