Подтвердить что ты не робот

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

Как я знаю JVM перед запуском приложения Java, он выделяет для него часть ОЗУ, и эта память может управляться пользователем перед запуском. Но есть еще одна проблема, когда я запускаю приложение, каждый раз он выполняет другое время.

Вот очень простой пример для цикла:

package timespent;

public class Main {

    public static void main(String[] args) {

        long startTime = System.nanoTime();

        int j = 0;

        for (int i = 0; i < 1.E6; i++) {
            j = i + 1;
        }

        long endTime = System.nanoTime();

        long duration = (endTime - startTime);

        System.out.println("duration = " + duration);
    }
}

Он печатает разные результаты:

duration = 5720542
duration = 7331307
duration = 7737946
duration = 6899173

Скажем, я хочу, чтобы он выполнялся точными 10 000 000 наносекунд или 10 миллисекунд.

Что мне нужно?

Я хочу, чтобы приложение java выполнялось с точным выполнением времени.

Зачем мне это нужно?

Когда я запускаю приложение, я хочу показать точное время выполнения, оставшееся в окне запуска приложения, прежде чем он загрузит все компоненты.

Я полагаю, что это своего рода манипуляция с процессором, и я хотел знать, возможно ли это или нет.

Q1: Возможно ли это на Java?
Q2: Если это невозможно в Java, то есть ли способ достичь этого, обратившись к родным методам ОС. например путем приоритизации приложения Java или чего-то еще?
Q3: Как сохранить состояние приложения в файле и загрузить его в память?

4b9b3361

Ответ 1

В вашем измерении времени существует ряд источников неопределенности. И все эти источники не просто влияют на ваши измерения, это сама среда выполнения, которая является неопределенной. Среди источников неопределенности:

  • Использование кэша (какие части памяти кэшируются в CPU). Ваши данные могут быть выведены из кеша вашим процессором, выполняющим фоновое задание.

  • Размещение памяти (это память, непосредственно подключенная к исполняющему ядру ЦП?). Это может измениться со временем, так как ваш процесс может быть перенесен в другое ядро ​​в любое время.

  • Программные прерывания (ваша ОС выгружает ваш процесс для запуска другого). Может быть несколько смягчено, работая на тихой машине, но нет никакой гарантии, что вы не прерветесь.

  • Термическое регулирование (ваш процессор решает, что он слишком горячий и отключает его тактовую частоту). Там действительно мало что можно сделать, если вы не готовы работать над встроенным процессором с фиксированной тактовой частотой.

  • Аппаратные прерывания (ваш сетевой разъем получил некоторые данные с другого компьютера в Интернете). Вы не имеете никакого влияния на то, когда это ударит, что бы то ни было.

  • Непредсказуемые задержки (вы читаете некоторые данные с диска, но сначала диск должен ждать, пока данные не появятся ниже считывающей головки). Это может следовать шаблонам, когда вы повторяете одни и те же действия снова и снова, но как только вы получите несвязанное аппаратное прерывание, это может вызвать неожиданную задержку 1/7200 rpm * 60 s/min = 8.3 ms.

  • Сбор мусора (вы спрашиваете о Java, поэтому у вас работает GC в фоновом режиме). Даже лучшие, самые современные сборщики мусора не могут в полной мере избегать остановки мира время от времени. И даже когда они не останавливают мир, они все еще работают в фоновом режиме, вводя шум во время работы через кеш, размещение в памяти и программные прерывания.

Это, вероятно, самые важные источники, и могут быть и другие. Дело в том, что ваш процесс никогда не одинок на машине. Если вы не запускаете без ОС и отключите все аппаратные прерывания, вам просто нужно жить с тем, что ваши временные ряды будут варьироваться от исполнения к исполнению, и просто нет возможности исправить это.

Ответ 2

Это просто невозможно. Прежде всего, измерение времени в наносекундах не является точным. Я чувствую, что этот пост объясняет это хорошо.

Во-вторых, вы не можете контролировать, как CPU планирует выполнение. Могут быть другие задачи, связанные с загрузкой процессорного времени, что задерживает выполнение вашей программы.

Ответ 3

Точное время выполнения произвольного кода не является детерминированным, потому что оно зависит от других вещей, которые выполняет физическая машина одновременно.

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

Когда и на сколько времени выполняются или ждут потоки, они не работают с программным обеспечением.

Ответ 4

[TL; DR] Это очень сложно/невозможно.

Более длинный ответ см. Тестирование планаризма по пути Дополнение PhD-тезис - методологическая глава по бенчмаркингу по некоторым вопросам, включая:

  • Другие приложения, имеющие ресурсы. То есть не имея достаточного объема памяти, а операционная система должна использовать страницы; или код работает медленнее, поскольку другое приложение использует CPU.
  • Разрешение часов - ваш код будет работать так же быстро, как ваш процессор. Поместите его на другой компьютер, и ваши тесты могут дать вам совершенно разные результаты, поэтому не оптимизируйте его только для вашей системы.
  • Загрузка класса - когда JVM сначала запускает код, он должен загружать классы в память (как правило, с диска) и анализировать байтовый код, поэтому при первом запуске будет значительно медленнее, чем в последующие моменты времени.
  • Компиляция Just-In-Time - когда JVM сначала загружает байтовый код, он запускает его в чисто интерпретируемом режиме. Как только он несколько раз запустил блок байтового кода (т.е. Одну функцию внутри вашего кода) (скажем, 10 000), он может скомпилировать эту функцию с помощью собственного кода. Компиляция замедлит это выполнение, но последующие вызовы будут быстрее, поскольку он запускает собственный, а не интерпретируемый код. Однако это не разовая компиляция, и если JVM видит, что некоторые пути выполнения в блоке предпочтительнее, тогда он может перекомпилировать байт-код, чтобы попытаться оптимизировать эти пути, и это может привести к нескольким собственным версиям байта до тех пор, пока JVM не стабилизирует код против его статистики.
  • Сбор мусора - иногда ваш код будет прерван, а Java вызывает сборщик мусора.

Итак, если вы хотите сравнить ваше приложение, чтобы увидеть, как он будет работать оптимально, выполните следующие действия:

  • Остановите столько других приложений, сколько сможете;
  • Запустите код много десятков тысяч раз;
  • Игнорировать первые 10 000 - 20 000 исполнений (для смягчения загрузки классов и компиляции JIT); и
  • Игнорируйте итерации при сборе мусора (это сложнее определить, чем кажется).

Это даст вам представление об оптимальной производительности, но оптимальный и реальный мир - это две разные вещи.

Ответ 5

Единственный способ приблизиться к этому - использовать в реальном времени Java в операционной системе, специально разработанной для поддержки выполнения в реальном времени,

Ответ 6

Как говорили другие, невозможно узнать точное время, оставшееся из-за других факторов, влияющих на скорость вашей программы. Тем не менее, вы могли бы разместить вехи и ссылаться на прошлые прогоны, чтобы получить полуточное время, вычисленное по дисперсии в фактическом времени, пока это выполняется по сравнению с предыдущими прогонами, как это делается при копировании больших каталогов файлов в Windows, например, или при загрузке больших файлов в Chrome.

Таким образом, вы не укажете свою точную проблему, но скажите, что это что-то вроде обработки 100 000 операций, которые требуют подключения к сторонней системе в Интернете, и обычно требуется ~ 15 минут. Вы можете отслеживать 1) Время начала, 2) Ожидаемое время окончания и 3) Порция завершена. Так что скажите, когда вы сделаете 1/2, вы можете пройти истекшее время и сказать, сколько времени осталось. В основном получите скорость в операциях в секунду и разделите оставшиеся операции на это, чтобы получить оставшееся количество секунд.

double speed = completedOperations / elapsedSeconds;
double remainingSeconds = remainingOperations / speed;

Однако это может измениться. Скажите, что вы запустили процесс и после того, как через 5 минут вы достигли 1/4 пути, что запускают резервные копии вне компании, а не только изматывают компьютерные диски, но ваше интернет-соединение. Теперь все обрабатывается на 1/10 скорости. Ваше предполагаемое время завершения начнется 20 минут, затем через 5 минут будет 15 минут. Однако он замедляется в этот момент, так что вы делаете всего лишь 1/2 после 30 минут, а оставшееся время на этом этапе будет 30 минут. Теперь скажем, что резервные копии завершены, вы действительно будете сделаны через 10 минут, но он говорит, что осталось 30 минут.

Невозможно избежать такой проблемы, которая не поддается контролю. Вы могли бы сделать пару вещей, чтобы смягчить это. Возможно, вы захотите принять скорость за последние 30 секунд обработки. Это будет самым точным, если все будет продолжаться с текущей скоростью. Вы можете записывать среднюю скорость в исторические моменты времени, если это проблема. Вы можете усреднить общую скорость и скорость последней минуты, если скорость колеблется.

Еще одна вещь, которая может его отбросить, - это дисперсия данных. Например, если вы рассматриваете клиентов и обрабатываете их на основе даты, когда они стали клиентами, ваши первые 10 000 операций могут быть у лояльных клиентов, которые были с вами в течение многих лет и имеют массу данных для обработки, в то время как последние 10 000 могут быть новыми клиентами с небольшими данными, которые работают быстрее. Затем вы можете использовать базовое количество данных вместо количества клиентов...


Однако, если вы хотите быть точным по какой-либо причине (большую часть времени), вы можете подделать его за счет времени. Возьмите наибольшее нормальное время работы и просто используйте время, затраченное с самого начала, чтобы обеспечить прогресс и оставшееся время. Затем, когда вся фактическая работа завершена, введите команду sleep(), чтобы подождать оставшееся время. Всегда будет вероятность того, что загрузка системы или что-то заставляет ее заняться исключительно долго, но вы можете изменить максимальное время на это новое значение.

Времена ваших прогонов, вероятно, на какой-то кривой, чем дольше вы набираете время, тем больше вероятность того, что какой-либо один запуск будет завершен за это время, но тогда больше запусков будет ждать ничего:

         #            ^
         #            |
        ###           |
        ###           |
       #####          R
      #######         U
    ###########       N
###################   S

Time-------------->

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

Ответ 7

Это не сработает. Это зависит от состояния системы, например, сколько системных ресурсов работает над вашей программой.

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

Но я могу дать предложение, вы можете просто прочитать данные своей программы и отрегулировать время на этой основе, как и другое приложение, которое показывает..% загружено или такое же, как функция диспетчера загрузки, которая показывает..% загружено.