Вопрос по thread-sleep, method-invocation, sleep, java, nanotime – Как приостановить поток Java на небольшой промежуток времени, например, 100 наносекунд?

26

я знаюThread.sleep() может сделать приостановку потока Java на некоторое время, например, в определенные миллисекунды и определенные наносекунды. Но проблема в том, что вызов этой функции также вызывает накладные расходы.

Например, если я хочу приостановить поток на 100 наносекунд, и я вызываюThread.sleep(0, 100), Вся стоимость этого процессаinvocation_cost + 100 nanosceonds, который может быть намного больше, чем я хочу. Как я мог избежать этой проблемы и достичь своей цели?

Мне нужно это потому, что я хочу делать симуляцию в автономном режиме. Я профилировал время выполнения задачи; Теперь я хочу смоделировать это время выполнения, приостановив поток в тот же период времени.

Спасибо!

@EntangledLoops Спасибо за предоставленный пример. Я не сомневаюсь, что для этого есть веские причины. Я считаю, что лучшие ответы часто принимают во внимание контекст, в котором был задан вопрос. Посмотрите на ответ Питера Лоури ниже, чтобы увидеть пример этого, когда ОП предоставил некоторую справочную информацию. g t
У вас есть конкретная причина, почему вы хотите это сделать? Если это так, это может быть решено по-другому ... g t
@ gt FYI, раздражает публиковать вопросы на stackoverflow и получать ответы на этот вопрос, а не давать ответ. Есть много веских причин для желания сделать это, которые возникли в проектах на протяжении многих лет. Одной из практических причин может быть поддержание поведения в реальном времени в приложениях, которые записывают аудио с аппаратного обеспечения, поскольку аппаратное обеспечение может работать нестабильно, или вы можете моделировать поведение аппаратного обеспечения в целях тестирования. EntangledLoops
Бывают случаи, когда полезны очень короткие сны, например, когда вы разговариваете с оборудованием, которое может принимать сообщения только со скоростью, меньшей, чем код контроллера, может доставлять их ему (но все же намного больше, чем тысяча сообщений в секунду). Этот вопрос (и его ответы) полезен в этих обстоятельствах. Donal Fellows
Это необычное требование. Похоже, вам нужноback off strategy или похожие. Bohemian♦

Ваш Ответ

5   ответов
22

Степень детализации снов обычно ограничена периодом прерывания планировщика потоков. В Linux этот период прерывания обычно составляет 1 мс в последних ядрах. В Windows период прерывани планировщика обычно составл ет около 10 или 15 миллисекунд.

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

EDITЯ подозреваю, что вы получите лучшие результаты на jrockit + solaris. Числа на коробке окна ужасны.

@Test
public void testWait(){
    final long INTERVAL = 100;
    long start = System.nanoTime();
    long end=0;
    do{
        end = System.nanoTime();
    }while(start + INTERVAL >= end);
    System.out.println(end - start);
}
Вы понимаете, что этот цикл съедает 100% одного ядра процессора? Это анти-паттерн ждать / спать.
Благодарю. Если вы используете напряженное ожидание, как вы можете контролировать продолжительность ожидания? как 100 наносекунд. JackWM
В наши дни вам придется много искать одноядерный процессор. Очевидно, он поддерживает процессор в течение нескольких наносекунд. Пожалуйста, прокомментируйте, если у вас есть альтернатива, которая решает заданный вопрос
Если>= быть<= ? JackWM
Вы, вероятно, должны ясно дать понять в этом ответе, что он побеждает процессор.
1

Ожидание занято (т. Е. Проведите цикл цикла по стольким числам, которые ничего не делают). В начале вашей программы вы можете рассчитать время, которое потребовалось ей, чтобы выполнить это занятое ожидание, и увеличить или уменьшить его, чтобы получить до 5 наносекунд.

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

3
public static void busySleep(long nanos)
{
  long elapsed;
  final long startTime = System.nanoTime();
  do {
    elapsed = System.nanoTime() - startTime;
  } while (elapsed < nanos);
}
1

Еще одна проблема сThread.sleep() является то, что он не гарантированно активируется после указанного времени. Спящая нить гарантируется для сна в течение указанных нано / микросекунд, но не гарантируется для немедленного пробуждения после этого. Поскольку вы говорите интервалы наносекунд, вы можете попробоватьObject.wait(long, int).

Я вполне соответствовал порядку 10 с наносекунд с вышеупомянутым методом.

Кроме того, в кодеObject.wait(timeout, nanos) вы можете увидеть, что еслиnanos > 0 это только увеличиваетtimeout на 1
В обоих случаях, когда вы вызываетеThread.sleep() а такжеObject.wait() текущий запущенный поток переходит вTIMED_WAITING Режим. Это подразумевает, что поток освобождает процессор. В обоих случаях, когда время ожидания заканчивается, процессор, скорее всего, будет занят чем-то другим. Нет никакой гарантии, что бодрствующий поток получит ЦП сразу, и даже если он это сделал, ему все равно придется заплатить время переключения контекста, что, в соответствии с вопросом, именно этого и хочет избежать запрашивающий.
13

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

Вместо этого я бы использовал данные, симулированные часы и запускал все как можно быстрее. Это дает воспроизводимые результаты и позволяет имитировать быстрее, чем в реальном времени (например, в 2–100 раз быстрее)


Подозрение на поток занимает около 10 микросекунд. Нет смысла пытаться приостановить поток на меньшее время, чем это.

Чтобы заняты ждать в течение короткого периода времени, вы можете попробовать.

long start = System.nanotime();
while(start + delay >= System.nanoTime());

Примечание: как комментирует @EugeneBeresovsky, после того, как ваша машина проработала 292 года, это может переполниться, поэтому вы можете написать это как

while(System.nanoTime() - start < delay);

Это будет штраф за задержки менее 292 лет. Вы можете использовать System.currentTimeMillis () для гораздо более длительных задержек.

Однако даже это ненадежно, так как System.nanoTime () может потребовать до 300 нс в Centos 5.x, поэтому его повторный вызов займет гораздо больше времени, чем 100 нс. Также многие ОС имеют разрешение только 1000 нс (1 микросекунда), поэтому этот цикл будет ожидать до 1 микросекунды независимо от того, какую задержку вы ищете.

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

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

@EugeneBeresovsky исправить, однако System.nanoTime () - это время работы машины в Windows, Linux, MacOSX, так что этого не произойдет, пока ваша машина не проработает 292 года.
@EugeneBeresovsky Длинное значение будет переполнено после того, как ваша машина будет работать в течение 292 лет ... Я обновлю свой ответ.
Ваше условие while страдает от целочисленной ошибки переполнения. Вы должны сравнить разницу двух результатов nanoTime () с некоторым абсолютным значением, как, например, сделано. @EntangledLoops, а не сравнивать два абсолютных значения nanoTime друг с другом.
Документы, на которые есть ссылка в последнем комментарии, также явно указывают на это:To compare two nanoTime values, one should use t1 - t0 < 0, not t1 < t0, because of the possibility of numerical overflow. Читая ваши изменения, можно (или нет) создать впечатление, что проблема связана с временными интервалами, превышающими 292 года (они есть, но ни одна программа не запускается так долго). Это не то, о чем я говорил. Это - все еще крайне маловероятный, но фактически возможный - случай, когда nanoTime переполняется между двумя вызовами - теоретически, даже если вызовы находятся на расстоянии лишь миллисекунд или менее друг от друга.
Хороший пост. Я редактировал & lt; чтобы & gt; = исправить код (в ретроспективе & quot; & gt; "еще лучше). Я сделал несколько других тривиальных изменений, чтобы достичь минимального редактирования символов 6 (argh). Благодарю.

Похожие вопросы