Почему на точность time.sleep () влияет Chrome? - PullRequest
23 голосов
/ 16 января 2020

Я заметил странное поведение, которое может указывать или не указывать c для моей системы. (lenovo t430 работает windows 8)

С этим сценарием:

import time

now = time.time()
while True:
    then = now
    now = time.time()
    dif = now - then
    print(dif)
    time.sleep(0.01)

Я получаю следующий вывод (что я бы назвал номинальным) с открытым браузером .

enter image description here

Однако без открытого браузера я наблюдаю серьезную задержку на l oop.

enter image description here

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

Буду признателен за любые идеи или простое копирование этих результатов.

РЕДАКТИРОВАТЬ: Интересно, я наблюдаю аналогичную задержку с этим кодом:

import time

now = time.time()

def newSleep(mark,duration):
    count = 0
    while time.time()-mark < duration:
        count+=1
    print(count)


while True:
    then = now
    now = time.time()
    dif = now - then
    print(dif)
    #time.sleep(0.01)
    newSleep(now,0.01)

Хотя это и дает дополнительное понимание - то есть некоторые случаи скрытых циклов происходят из-за недостаточной доступности процессора (отмечается счетчиком 0 при печати) - я все же замечаю поведение 15 мс, когда количество отпечатков будет достигать 70 тыс. и поведение 10 мс со счетом около 40 тыс.

Ответы [ 5 ]

15 голосов
/ 25 января 2020

Я дополнительно запустил Windows 7, чтобы повторить ваши выводы, и я могу подтвердить это.

Это вещь Windows с типом используемого таймера и разрешением по умолчанию: 15,6 мс (минимум 0,5 мс). Приложения могут изменять текущее разрешение (функция WinAPI: timeBeginPeriod ) и Chrome.

Эта функция влияет на глобальную настройку Windows. Windows использует самое низкое значение (то есть самое высокое разрешение), запрошенное любым процессом. Установка более высокого разрешения может повысить точность интервалов ожидания в функциях ожидания. Однако это также может снизить общую производительность системы, поскольку планировщик потоков переключает задачи чаще. Высокие разрешения также могут помешать системе управления питанием ЦП перейти в режимы энергосбережения. Установка более высокого разрешения не повышает точность счетчика производительности с высоким разрешением.

В статье за ​​2014 год в Forbes рассматривается ошибка in Chrome, который установил бы разрешение постоянно на 1 мс независимо от того, какая текущая нагрузка потребовалась бы - проблема, потому что это общесистемный эффект, влияющий на потребление энергии. Из этой статьи:

В таких ОС, как Windows, события часто устанавливаются с интервалами. Чтобы сэкономить энергию, процессор спит, когда ничто не требует внимания, и просыпается с заданными интервалами. Этот интервал регулируется Chrome в Windows, поэтому его уменьшение до 1.000 мс означает, что система просыпается гораздо чаще, чем при 15.625 мс. Фактически, при 1.000 мс процессор просыпается 1000 раз в секунду. Значение по умолчанию, равное 15,625 мс, означает, что процессор просыпается всего 64 раза в секунду, чтобы проверять события, требующие внимания.

Сама Microsoft говорит, что частота тиков в 1000 мс может увеличить энергопотребление на «до 25%». ".

Вы можете получить разрешение по умолчанию от Python с помощью time.get_clock_info () .

namespace = time.get_clock_info('time')
namespace.adjustable
# True
namespace.implementation
# 'GetSystemTimeAsFileTime()'
namespace.monotonic
# False
namespace.resolution
# 0.015600099999999999

Фактическое разрешение можно получить из cmd с помощью апплета ClockRes .

8 голосов
/ 21 января 2020

Я пытался сделать то же самое в windows и на сервере Ubuntu (virtualbox) (у которого нет браузера), но результат такой же, в среднем я получаю

на сервере Ubuntu

    0.010122537612915039
    0.010426998138427734
    0.010067939758300781
    0.010767221450805664
    0.010728120803833008
    0.010106086730957031
    0.01068258285522461
    0.010105609893798828
    0.01118612289428711
    0.010136842727661133
    0.010585784912109375
    0.010425567626953125
    0.01014852523803711
    0.010422945022583008
    0.01010894775390625

и Windows

    0.010767221450805664
    0.010751485824584961
    0.010716915130615234
    0.010229110717773438
    0.01016545295715332
    0.010195255279541016
    0.010723352432250977
    0.010744094848632812
    0.010716438293457031
    0.010564565658569336
    0.010889291763305664
    0.010728597640991211
    0.010579824447631836
    0.010889530181884766
    0.010567903518676758
    0.010717153549194336
    0.010735273361206055

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

6 голосов
/ 22 января 2020

Хотя я не могу воспроизвести это поведение на своем компьютере, я подозреваю, что оно может быть вызвано динамическим c тактовым сигналом процессора (а также тактовой частотой памяти и системной шины), например, если у вас нет открытого браузера, то процессор работает на 1/2 максимальной частоты, но как только вы запускаете браузер, он достигает максимальной частоты. Вы можете убедиться в этом, поиграв с «Максимум \ минимальное состояние процессора \ частота» в Advanced Power Options или запустив другое приложение, которое порождает много процессов (это то, что делает Chrome) вместо браузера, и посмотрите, не изменит ли это время ожидания.

6 голосов
/ 16 января 2020

Буду признателен за любые идеи или простое копирование этих результатов.

Здесь вы go:

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

Я измерил среднее время выполнения -

Браузер работает: 0,01055538261329734

Браузер не работает: 0,01563055389053695

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

Ждем дальнейших идей.

2 голосов
/ 26 января 2020

Я написал аналогичный код и получил аналогичные результаты,

for i in range(10):
    then = time.time()
    time.sleep(0.01)
    now = time.time()
    # print('+---------------------------+')
    print(now - then)
    # print(f"rounded: {round(now - then, 2)}")
    # print('+---------------------------+')

Сначала я подозревал, что причина в том, что использование математики с плавающей запятой проверьте это .

Но потом я получил этот вывод

Выходы

0.01080012321472168
0.01015472412109375
0.010109186172485352
0.022491931915283203 # THIS ONE IS REALLY WEIRD
0.01163029670715332
0.010137796401977539
0.010179996490478516
0.01008749008178711
0.010132551193237305
0.010088443756103516

Даже если вы предполагали, что при расчете разницы есть предел погрешности, он не должно быть так много

+---------------------------+
0.01080012321472168
rounded: 0.01
+---------------------------+
+---------------------------+
0.01015472412109375
rounded: 0.01
+---------------------------+
+---------------------------+
0.010109186172485352
rounded: 0.01
+---------------------------+
+---------------------------+
0.022491931915283203
rounded: 0.02                 
+---------------------------+
+---------------------------+
0.01163029670715332
rounded: 0.01
+---------------------------+
+---------------------------+
0.010137796401977539
rounded: 0.01
+---------------------------+
+---------------------------+
0.010179996490478516
rounded: 0.01
+---------------------------+
+---------------------------+
0.01008749008178711
rounded: 0.01
+---------------------------+
+---------------------------+
0.010132551193237305
rounded: 0.01
+---------------------------+
+---------------------------+
0.010088443756103516
rounded: 0.01
+---------------------------+

Но после прочтения официальной документации python метода time.sleep эти результаты имеют смысл проверьте здесь , я цитирую документацию

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

Так что в качестве обоснованного предположения о проблеме здесь,

Это вызвано несколькими факторами

  1. Планирование потоков операционной системы
  2. Время выполнения до и после сна
  3. И, вычисление с плавающей точкой .

Я надеюсь, что это помогло.

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