Python - запуск программы каждые 10 секунд, datetime.now () меняет поведение - PullRequest
1 голос
/ 16 июня 2020

Я тестировал программу, выполняющую что-то каждые N секунд, но столкнулся со странной проблемой.

Если я использую что-то простое вроде этого:

import time

def main():
    start_t = time.time()

    while(True):
        if (time.time()-start_t)%10 == 0:
            print("Test")

if __name__ == "__main__":
    main()

программа работает как ожидается, т.е. он печатает «Тест» каждые 10 секунд.

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

import time
from datetime import datetime


def main():
    start_t = time.time()
    path_screenshots = "screenshots"

    while(True):
        path_screenshots_today = f"{path_screenshots}/{datetime.now().strftime('%Y_%m_%d')}/"
        if (time.time()-start_t)%10 == 0:
            print(f"Checking folder {path_screenshots_today}...")

if __name__ == "__main__":
    main()

я бы ожидал, что программа для повторной печати «Проверка папки {path_screenshots_today}» каждые 10 секунд, но вместо этого она продолжает работать, ничего не печатая. Я понимаю, что результат операции (time.time () - start_t)% 10 никогда не бывает точно равен 0, что может создавать проблему ... но тогда почему это вообще работает в первом случае?

Ответы [ 3 ]

2 голосов
/ 16 июня 2020

Я подозреваю, что в первом случае он работает, потому что l oop работает достаточно быстро, чтобы выстроиться в линию. Задержка, вызванная созданием path_screenshots_today (особенно вызова datetime.now()), заставляет его не выстраиваться так часто. Чтобы сделать то, что вы хотите, попробуйте:

import time
from datetime import datetime


def main():
    last = time.time()
    path_screenshots = "screenshots"

    while True:
        path_screenshots_today = f"{path_screenshots}/{datetime.now().strftime('%Y_%m_%d')}/"
        if time.time() - last >= 10:
            last = time.time()
            print(f"Checking folder {path_screenshots_today}...")

if __name__ == "__main__":
    main()
1 голос
/ 16 июня 2020

Это совпадение того, как часто происходит проверка. Если вы на самом деле l oop поверх и напечатаете свое значение, вы заметите, что оно с плавающей запятой:

    while(True):
        print('Current value is, ', (time.time()-start_t)%10)

Вы увидите следующий результат:

Current value is,  0.45271849632263184
Current value is,  0.45272231101989746

Учитывая, что вы вы так мало делаете в своем l oop, велика вероятность, что вы случайно сделаете эту оценку, когда текущее значение точно 0.0. Но когда вы добавляете некоторые дополнительные вычисления, даже просто форматирование строки в datetime, каждая итерация вашего l oop займет немного больше времени, и вы можете просто пропустить 0.0.

Итак, строго говоря, вы должны преобразовать свое значение в int, прежде чем сравнивать его с 0. Например, int((time.time() - start_t) % 10) == 0. Это будет верно в течение целой секунды, пока значение модуля снова не станет отличным от нуля, через секунду после того, как оно стало истинным.

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

time.sleep(10)   # Sleep for 10 seconds
1 голос
/ 16 июня 2020

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

start_t = time.time()
while True:
    path_screenshots_today = f"{path_screenshots}/{datetime.now().strftime('%Y_%m_%d')}/"
    tt = time.time()
    if tt - start_t >= 10:
        print(f"Checking folder {path_screenshots_today}...")
        start_t = tt  # set last check time to "now"

И еще лучший способ:

while True:
    path_screenshots_today = f"{path_screenshots}/{datetime.now().strftime('%Y_%m_%d')}/"
    print(f"Checking folder {path_screenshots_today}...")
    time.sleep(10)

Это позволяет избежать «занятого ожидания», т.е. 1007 *

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