Учебник по запуску программы на Python с регулярным интервалом времени с помощью модуля времени и даты

Этот учебник научит вас, как настроить программу на Python для запуска через регулярные промежутки времени с помощью модуля time и datetime. Это полезно, если вы хотите постоянно что-то проверять, и у вас есть программа python, работающая в фоновом режиме и выполняющая проверку за вас через регулярные промежутки времени.

Решение

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

Простое решение, если то, что вы делаете, является легковесным

Легкий вес означает, что он не использует много мощности и времени процессора, как, например, простая функция печати.

Предположим, что вы хотите запускать код каждые 10 секунд.

import time
from datetime import datetime

def do_things():
    print(datetime.now())

while True:
    do_things()
    time.sleep(10)

Вход в полноэкранный режим Выйдите из полноэкранного режима

вы должны получить что-то вроде этого

2022-08-24 10:59:35.247516
2022-08-24 10:59:45.259224
2022-08-24 10:59:55.272715
2022-08-24 11:00:05.284097
2022-08-24 11:00:15.290823

Вход в полноэкранный режим Выйти из полноэкранного режима

Вот и все, вы можете заменить время сна, если вам нужен другой интервал, и вы можете заменить содержимое функции do_things() на то, что вы хотите, чтобы программа сделала.

Проблема с простым решением

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

import time
from datetime import datetime

def do_things():
    number = 50_000_000
    sum(i*i for i in range(number))
    print(datetime.now())

while True:
    do_things()
    time.sleep(10)

Вход в полноэкранный режим Выход из полноэкранного режима

Здесь я использовал sum(i*i for i in range(number)) на огромном числе, чтобы заставить процессор проделать много работы, не обращайте внимания на подчеркивание в 50_000_000, это то же самое, что 50000000. Результат работы этой программы таков:

2022-08-24 11:07:54.377208
2022-08-24 11:08:07.599538
2022-08-24 11:08:20.838108
2022-08-24 11:08:34.043164
2022-08-24 11:08:47.255688

Вход в полноэкранный режим Выход из полноэкранного режима

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

Расширенное решение

import time
from datetime import datetime, timedelta

def do_things():
    number = 50_000_000
    sum(i*i for i in range(number))
    print(datetime.now())

while True:
    previous_datetime = datetime.now()
    do_things()
    time_took_running_do_things = datetime.now() - previous_datetime
    remaining_time_in_secs = (timedelta(seconds=10) - time_took_running_do_things).total_seconds()
    time.sleep(remaining_time_in_secs)

Вход в полноэкранный режим Выйти из полноэкранного режима

и получите результат:

2022-08-24 11:14:40.821099
2022-08-24 11:14:50.797054
2022-08-24 11:15:00.806950
2022-08-24 11:15:10.834795
2022-08-24 11:15:20.845102

Войти в полноэкранный режим Выйти из полноэкранного режима

Пояснение

Здесь видно, что коды выполняются каждые 10 секунд, несмотря на то, что мы делаем большую работу. Это происходит потому, что мы компенсировали время, затраченное на выполнение do_things(), меньшим временем ожидания. Если программе потребовалось 3 секунды на выполнение do_things(), то после этого мы ждем только 7 секунд, поэтому программа по-прежнему выполняет действия каждые 10 секунд.

Ограничение

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

Как я до этого дошел

Теперь я расскажу о том, как я до этого додумался.

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

Сначала я подумал, что это проблема с time.sleep(), возможно, из-за того, что процессор выполняет много работы во время игры, ожидание неправильное.

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

Тогда я закомментировал то, что программа делает в каждом интервале, оставив только оператор print time, и проблема была устранена. Оказалось, что проблема в том, что то, что я делаю внутри интервала, стоит больше 2 секунд!

После этого я сразу же попытался пересмотреть проблему. Я подумал, может быть, я хочу, чтобы цикл и функция do_things() выполнялись в отдельных потоках с помощью потоковой обработки или asyncio, а может быть, даже в отдельных CPU с помощью мультипроцессинга. Я просмотрел весь учебник «Speed Up Your Python Program With Concurrency» Джима Андерсона на RealPython, пока не нарисовал этот график.

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

Оцените статью
devanswers.ru
Добавить комментарий