Существует ли библиотека Python или решение, которое будет выполняться с минутной или часовой отметкой? - PullRequest
0 голосов
/ 05 ноября 2019

Моя цель - запустить программу на разных компьютерах и получить данные измерений. Проблема в том, что эти измерения должны проводиться одновременно (насколько это возможно). Мой текущий подход заключается в установке crony для синхронизации времени всех машин и запуске программы на python, которая будет проводить измерения в начале каждой минуты. Это оказалось довольно громоздким, так как я должен опрашивать time.time () в цикле и проверять, не введена ли новая минута.

time_factor = 1   # 1000 if desired resolution is ms, 1 if seconds
interval_s = 60 * time_factor
old_interval = int(time.time()*time_factor) / interval_s
current_interval = None
running = True
while running:
    t_s = int(time.time() * time_factor)
    current_interval = t_s / interval_s

    if (t_s % interval_s == 0) and (current_interval != old_interval):
        request_runtime = time.time()

        await self.do_time_sensitive_work()

        old_interval = current_interval
        request_runtime = time.time() - request_runtime
        await asyncio.sleep(int(interval_s - request_runtime - 1))
    else:
        await asyncio.sleep(0.01)

Есть ли стандартное решение для этого типа проблемы или, по крайней мере, более элегантное решение?

Ответы [ 3 ]

0 голосов
/ 06 ноября 2019

Попробуйте это:

import asyncio
import time
from datetime import datetime


async def task(call_time):
    print(f"task started at: {to_string(call_time)}")
    await asyncio.sleep(5)
    print(f"task finished at: {to_string((time.time()))}")


def to_string(t):
    return datetime.utcfromtimestamp(t).strftime('%Y-%m-%d %H:%M:%S')


def call_task(loop, task, *args):
    print("task creating")
    loop.create_task(task(*args))
    print("task created")


async def main(loop: asyncio.AbstractEventLoop):
    interval = 10
    t = time.time()
    while True:
        print(f"Now is {to_string(t)}")
        call_time = estimate_next_call(t, interval)
        print(f"Call time {to_string(call_time)}")
        await asyncio.sleep(call_time - t)
        call_task(loop, task, call_time)
        t += interval
        await asyncio.sleep(interval)


def estimate_next_call(t, interval):
    return ((t + interval) // interval) * interval


if __name__ == "__main__":
    event_loop = asyncio.get_event_loop()
    event_loop.run_until_complete(main(event_loop))
0 голосов
/ 07 ноября 2019

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

Я также пытался использовать сельдерея , однако это кажется большим излишним, необходимость установить Redis или что-то еще в качестве брокера сообщений, и использование такой сложной инфраструктуры для такой незначительной задачи просто кричит "неправильный ".

Текущее решение, которое работает достаточно быстро, основано на изменении разрешения проверок времени с использованием" time_factor "для изменения значений time.time () в секундах. Основная часть решения - это деление текущего времени с интервалом, чтобы получить сердечный номер интервала в истории. Если это число изменилось, мы только что ввели новый интервал:

time_factor = 100  # 1000 for milliseconds
interval_size = 60 * time_factor
sleep_time = 1 / (time_factor * 100)
old_interval = int(int(time.time()*time_factor) / interval_size)
current_timestamp = time.time()
current_interval = None

running = True
while running:
    current_timestamp = int(time.time() * time_factor)
    current_interval = int(t_s / interval_size)
    if (current_interval != old_interval):
        request_runtime = time.time()

        await self.do_time_sensitive_work()

        old_interval = current_interval
        request_runtime = time.time() - request_runtime
        await asyncio.sleep(1/(time_factor*100) - request_runtime )
    else:
        await asyncio.sleep(1/(time_factor*100))
0 голосов
/ 05 ноября 2019

Может быть, это то, что вы ищете

Каков наилучший способ повторного выполнения функции каждые x секунд в Python?

Не могу комментировать, так как у меня нет репутации TT

...