Проверьте непрерывное состояние со временем - PullRequest
0 голосов
/ 02 февраля 2019

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

import thread
import time


# Define a function for the thread
def check_message (last, timer):
    oldtime = time.time()
    print oldtime
    # check
    while time.time() - oldtime <= 60:
    print (time.time() - oldtime)
    print "One minute"+ str(time.time())
    return 1

# Create two threads as follows
try:
    named_tuple = time.localtime() # get struct_time
    time_string = time.strftime("%H:%M:%S", named_tuple)
    thread.start_new_thread(check_message , (time_string, 60))
except:
    print "Error: unable to start thread"

while 1:
    pass

Спасибо!

Ответы [ 2 ]

0 голосов
/ 03 февраля 2019

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

В моем примере ниже я использую пользовательский класс менеджера TimeLord, чтобы преодолеть это ограничение.TimeLord позволяет «сбросить» таймер, отменив текущий таймер и заменив его новым.Для этой цели TimeLord содержит промежуточную промежуточную рабочую функцию и атрибут token, который должен быть запущен запущенным экземпляром таймера для выполнения указанной целевой функции.

Этот дизайн гарантирует уникальное выполнение указанной целевой функции, поскольку dict.pop() является атомарной операцией.timelord.reset() действует до тех пор, пока текущий таймер не запустил свой поток и не вытолкнул _token.Этот подход не может полностью предотвратить потенциально неэффективные запуски новых потоков таймера при попытке «перезагрузки», но это некритическая избыточность, когда это происходит, поскольку целевая функция может быть выполнена только один раз.

Этот код работает с Python2 и 3:

import time
from datetime import datetime
from threading import Timer, current_thread


def f(x):
    print('{} {}: RUNNING TARGET FUNCTION'.format(
        datetime.now(), current_thread().name)
    )
    time.sleep(x)
    print('{} {}: EXITING'.format(datetime.now(), current_thread().name))


class TimeLord:
    """
    Manager Class for threading.Timer instance. Allows "resetting" `interval`
    as long execution of `function` has not started by canceling the old
    and constructing a new timer instance.
    """
    def worker(self, *args, **kwargs):
        try:
            self.__dict__.pop("_token") # dict.pop() is atomic
        except KeyError:
            pass
        else:
            self.func(*args, **kwargs)

    def __init__(self, interval, function, args=None, kwargs=None):
        self.func = function
        self.args = args if args is not None else []
        self.kwargs = kwargs if kwargs is not None else {}
        self._token = True
        self._init_timer(interval)

    def _init_timer(self, interval):
        self._timer = Timer(interval, self.worker, self.args, self.kwargs)
        self._timer.daemon = True

    def start(self):
        self._timer.start()
        print('{} {}: STARTED with `interval={}`'.format(
            datetime.now(), self._timer.name, self._timer.interval)
        )

    def reset(self, interval):
        """Cancel latest timer and start a new one if `_token` is still there.
        """
        print('{} {}: CANCELED'.format(datetime.now(), self._timer.name))
        self._timer.cancel()

        # reduces, but doesn't prevent, occurrences when a new timer
        # gets created which eventually will not succeed in popping
        # the `_token`. That's uncritical redundancy when it happens.
        # Only one thread ever will be able to execute `self.func()`

        if hasattr(self, "_token"):
            self._init_timer(interval)
            self.start()

    def cancel(self):
        self._timer.cancel()

    def join(self, timeout=None):
        self._timer.join(timeout=timeout)

def run_demo(initial_interval):

    print("*** testing with initial interval {} ***".format(initial_interval))
    tl = TimeLord(interval=initial_interval, function=f, args=(10,))
    tl.start()

    print('*** {} sleeping two seconds ***'.format(datetime.now()))
    time.sleep(2)

    tl.reset(interval=6)
    tl.reset(interval=7)
    tl.join()
    print("-" * 70)


if __name__ == '__main__':

    run_demo(initial_interval=5)
    run_demo(initial_interval=2)

Пример вывода:

*** testing with initial interval 5 ***
2019-06-05 20:58:23.448404 Thread-1: STARTED with `interval=5`
*** 2019-06-05 20:58:23.448428 sleeping two seconds ***
2019-06-05 20:58:25.450483 Thread-1: CANCELED
2019-06-05 20:58:25.450899 Thread-2: STARTED with `interval=6`
2019-06-05 20:58:25.450955 Thread-2: CANCELED
2019-06-05 20:58:25.451496 Thread-3: STARTED with `interval=7`
2019-06-05 20:58:32.451592 Thread-3: RUNNING TARGET FUNCTION
2019-06-05 20:58:42.457527 Thread-3: EXITING
----------------------------------------------------------------------
*** testing with initial interval 2 ***
2019-06-05 20:58:42.457986 Thread-4: STARTED with `interval=2`
*** 2019-06-05 20:58:42.458033 sleeping two seconds ***
2019-06-05 20:58:44.458058 Thread-4: RUNNING TARGET FUNCTION
2019-06-05 20:58:44.459649 Thread-4: CANCELED
2019-06-05 20:58:44.459724 Thread-4: CANCELED
2019-06-05 20:58:54.466342 Thread-4: EXITING
----------------------------------------------------------------------

Process finished with exit code 0

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

0 голосов
/ 02 февраля 2019

Одним из вариантов будет проверка вне потока, чтобы основной цикл выполнял поток каждые 60 секунд, который выполняет работу X:

import threading
import time

# Define a function for the thread
def check_message():
    print("One minute"+ str(time.time()))
    return 1

last_execution = time.time()
while 1:
    if time.time() - last_execution < 60:
        time.sleep(1)
    else:
        last_execution = time.time()
        threading.Thread(target=check_message).start()
        # Python2:
        # import thread
        # thread.start_new_thread(check_message)

Я поменял код на работающий синтаксисв Python3, так как у меня не установлен Python2.Но общая идея должна работать одинаково в обеих версиях.

...