Использование многопоточности для тайм-аута выполнения блока - PullRequest
0 голосов
/ 11 июля 2019

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

class Runner:
    def __init__(self, *args, **kwargs):
        # init...
        self.start = None
        self.timeout = 60  # 1 minute for instance
        self.timedout = False

    def countdown():
        while not self.timedout:
            self.timedout = time.time() - self.start > self.timeout

    def run():
        # stuff
        self.start = time.time()
        t = multithreading.Thread(target=self.countdown)
        t.start()
        # do various things, call the chain of methods...
        t.join()

А затем мы просто проверяем self.timedout в соответствующих методах.

Я знаю, что мог бы использовать multiprocessing и обернуть весь блок выполнения процесса тайм-аутом, но (a) мне нужно точно настроить выход из методов вниз по линии, я не могу просто прервать процесс, потому что это может испортить состояние и (б) я даже не могу использовать Process из-за какой-то ошибки рассола.

Меня беспокоит метод coundown: вызовет ли time.time() огромное количество раз, что повлияет на производительность? Я рассматриваю возможность спать нить, например, 1 секунда во время цикла. Но опять же, я не уверен, как реальный механизм ожидания потока может повлиять на производительность. Если это влияет только на производительность потока, в котором он выполняется, тогда я в порядке, но если это влияет на выполнение в целом, это не нормально.

Ответы [ 2 ]

0 голосов
/ 11 июля 2019

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

Тем не менее, я рекомендую использовать Timer из модуля threading.

Этот класс представляет действие, которое должно выполняться только послеопределенное количество времени прошло - таймер.Timer является подклассом Thread [...]

Timer.cancel() позволяет остановить таймер, пока он находится в состоянии ожидания (хотя это может бытьвызывается впоследствии без какого-либо эффекта).Это позволяет завершить метод run до истечения интервала времени ожидания, а self.timedout остаться ложным, если не истекло время ожидания.

class Runner:
    def __init__(self):
        self.timedout = False
        self.timeout_sec = 60

    def _set_timeout(self):
        self.timedout = True

    def run(self):
        timer = Timer(self.timeout_sec, function=self._set_timeout)
        timer.start()
        # do various things, call the chain of methods...
        timer.cancel()

Можно избавиться от _set_timeoutметод с использованием lambda.Хотя это кажется немного неуклюжим.Поскольку тело лямбда-выражения должно быть выражением, а var = True - выражением, необходимо использовать setattr и передать экземпляр в лямбду:

timer = Timer(self.timeout_sec, function=lambda inst: setattr(inst, "timedout", True), args=(self,))

Другой вариант - сделать self.timedout an Event и вызовите его метод set(), чтобы сообщить об истечении времени ожидания.

self.timedout = Event()
[...]
timer = Timer(self.timeout_sec, function=lambda to: to.set(), args=(self.timedout,))

Проверка того, произошло ли событие тайм-аута, будет выполняться черезEvent.is_set():

if self.timedout.is_set():
    [...]
0 голосов
/ 11 июля 2019

Функция join() принимает необязательный параметр, который является значением времени ожидания. Вы можете установить значение тайм-аута t.join(no_of_seconds), и процесс вернется, если он завершится, или если он превысит порог тайм-аута. Используйте t.isAlive(), чтобы проверить, запущен ли еще процесс, завершите его и после этого установите поле времени ожидания класса.

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