Страницы

Поиск по вопросам

воскресенье, 8 марта 2020 г.

Отслеживание бездействия Python

#python #распараллеливание #timeout


Добрый день!
Подскажите, пожалуйста, как можно реализовать выполнение функции на Python в консольном
приложении по таймауту?

Смысл в следующем: Есть консольное приложение, которое идет своим чередом и периодически
требует от пользователя каких-либо действий. В случае же, если пользователь проявляет
бездействие в течение определенного времени, необходимо выполнить определенную функцию.

Из того, что есть:
Функция для отслеживания времени (Пример):

StartTime = time.time()  // В теле программе отслеживаем время последнего действия
TimeOut = 2000
def countTime():
   CurTime = time.time() // текущее время
   If CurTime > (StartTime+TimeOut): // проверяем разницу между текущим временем
и последним действием, сравниваем с таймаутом
      print SomeFunction() // выполняем необходимую функцию


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

Заранее спасибо!
    


Ответы

Ответ 1



если пользователь проявляет бездействие в течение определенного времени, необходимо выполнить определенную функцию. Общий подход: запланировать выполнение функции на определённое время и при любой активности пользователя переносить запуск на более позднее время. Чтобы просто запланировать выполнение функции func через 5 секунд в Питоне, не блокируя основной поток: import threading timer = threading.Timer(5, func) timer.start() Если timer.cancel() (отмена) не вызвать, то через 5 секунд будет вызвана func() в фоновом потоке. Чтобы адаптировать для вашей задачи, необходимо метод restart() добавить, который запустит отсчёт заново, при любой активности пользователя. Этот подход достаточно распространён, чтобы своё имя заработать: Watchdog timer — букв. «сторожевой пёс»: watchdog = WatchdogTimer(timeout, func, daemon=True) watchdog.start() # ... здесь программа что-то делает # и перезапускает отсчёт при любой активности пользователя watchdog.restart() # в конце отменяем вызов func совсем или просто из программы выходим watchdog.cancel() где WatchdogTimer класс определён здесь. Вот пример кода, где Питон-скрипт завершается, если пользователь не активен больше заданного времени в X (на Unix). Необязательно потоки использовать, например, в программе, использующей asyncio: async def watchdog(loop, last_activity_time, timeout, func, *args): "Run *func(*args)* if more than *timeout* seconds since *last_activity_time*." while (loop.time() - last_activity_time()) < timeout: await asyncio.sleep(1) return func(*args) Цель данной реализации—простота: пока разница между текущим временем (loop.time()) и записанным временем последней активности пользователя (last_activity_time()) меньше заданного значения (timeout), спим. В противном случае вызываем заданную функцию (func). Можно придумать решение, которое не использует asyncio.sleep(1). Пример использования: #!/usr/bin/env python3 import asyncio import random loop = asyncio.get_event_loop() user = {'last_activity': loop.time()} asyncio.ensure_future(watchdog(loop, lambda: user['last_activity'], 5, print, 'idle')) async def simulate_activity(): for i in range(20): print(i) if random.random() < .1: user['last_activity'] = loop.time() # user have done something now await asyncio.sleep(1) loop.run_until_complete(simulate_activity()) Программа печатает idle, если пользователь, имитированный с помощью random в simulate_activity() coroutine, слишком долго не показывает активности.

Ответ 2



import multiprocessing.pool, threading, random, time P = multiprocessing.pool.ThreadPool(processes=1) def timeout_fn(fn: object, *args, __timeout=10, **kwargs): '''выполнение функции на Python в консольном приложении по таймауту''' f = P.apply_async(fn, args, kwargs) return f.get(__timeout) def thread_fn(fn, *args, **kwargs): '''запускать функцию параллельно выполнению основного алгоритма программы''' t = threading.Thread(target=fn, args=args, kwargs=kwargs) t.start() def timeout_err(): print('если пользователь проявляет бездействие в течение определенного времени, необходимо выполнить определенную функцию') def main(timeout=5): while True: print('Есть консольное приложение, которое идет своим чередом') if random.randrange(0, 3): print('и периодически требует от пользователя каких-либо действий') try: # выполнение функции на Python в консольном приложении по таймауту r = timeout_fn(input, '\tВведите число:\n', __timeout=timeout) except multiprocessing.context.TimeoutError: print('ERR TIMEOUT %s' % timeout) timeout_err() else: print('[ %s ]' % r) finally: m = 'запускать функцию параллельно (асинхронно?) выполнению основного алгоритма программы.' thread_fn(lambda: print(m) or time.sleep(60)) if __name__ == '__main__': main() out: Есть консольное приложение, которое идет своим чередом Есть консольное приложение, которое идет своим чередом и периодически требует от пользователя каких-либо действий Введите число: 123 [ 123 ] запускать функцию параллельно (асинхронно?) выполнению основного алгоритма программы. Есть консольное приложение, которое идет своим чередом Есть консольное приложение, которое идет своим чередом и периодически требует от пользователя каких-либо действий Введите число: ERR TIMEOUT 5 если пользователь проявляет бездействие в течение определенного времени, необходимо выполнить определенную функцию запускать функцию параллельно (асинхронно?) выполнению основного алгоритма программы. Есть консольное приложение, которое идет своим чередом ...

Комментариев нет:

Отправить комментарий