python: как сделать периодический неблокирующий поиск

Не могли бы вы посоветовать, как периодически выполнять задачу, выполнение которой занимает больше времени, чем периодический интервал?

Например:

def lookup():
    # do some lookups, retrieve info, let's assume it takes 60sec to complete
    msg = {'abc':123}
    time.sleep(60)
    return msg

class Publisher(object):
    def __init__(self):
        self._TIMEIT = 0
        self._INTERVAL = 5
        self._counter = 0

    def xxx():
        t_start = time.time()
        msg = lookup()
        # do something with the value returned
        save_msg_to_db(msg)
        self._counter += 1
        t_end = time.time()
        self._TIMEIT = int(math.ceil(t_end - t_start))

    def run():
        while True:
            # let's do the lookup every 5sec, but remember that lookup takes 60sec to complete
            time.sleep(self._INTERVAL)
            # the call to xxx() should be non-blocking
            xxx()

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

Я думаю создать цикл обработки событий при каждом вызове функции xxx, как описано в Плохой пример сопрограммы, но как сделать вызов xxx неблокирующим?

PS. Я использую Python3.4, новый для asyncio (в прошлом использовал gevent), не уверен, что я спрашиваю здесь что-то глупое.

Таким образом, lookup создаст асинхронный цикл, который займет, скажем, 60 секунд. Но в методе run работает бесконечный цикл, и я хотел бы, чтобы он выполнял поиск каждые 5 секунд, другими словами, я хотел бы (1) как часто я вызываю функцию поиска, независимо от (2) сколько времени требуется для завершения поиска


person nskalis    schedule 26.06.2017    source источник
comment
Ваша функция lookup() интенсивно использует ЦП или ее выполнение занимает много времени из-за операций ввода-вывода?   -  person zwer    schedule 27.06.2017
comment
: это занимает много времени из-за операций ввода-вывода   -  person nskalis    schedule 27.06.2017
comment
А что происходит во время работы lookup()? Если вы хотите запустить его в фоновом режиме (не блокируя), и для его завершения требуется 60 секунд, и вы вызываете его каждые 5 секунд, довольно скоро у вас будут тысячи таких запущенных. Так что что-то должно дать - либо ваш интервал проверки (его продление), либо вызовы функции lookup() (не делайте еще один вызов, если предыдущий не завершился).   -  person zwer    schedule 27.06.2017
comment
@zwer хорошо, я рассчитываю на то, что будет 60/5 = 12 задач более или менее все время, и меня это вполне устраивает   -  person nskalis    schedule 27.06.2017


Ответы (1)


Поскольку ваш lookup() в основном интенсивно использует ввод-вывод, вы можете запустить свой метод xxx() как поток и все будет в порядке (код сокращен для краткости):

import threading
import time

class Publisher(object):

    def __init__(self):
        self._INTERVAL = 5
        self._counter = 0
        self._mutex = threading.Lock()

    def xxx(self):
        msg = lookup()
        save_msg_to_db(msg)
        with self._mutex:  # make sure only one thread is modifying counter at a given time
            self._counter += 1

    def run(self):
        while True:
            time.sleep(self._INTERVAL)
            t = threading.Thread(target=self.xxx)
            t.setDaemon(True)  # so we don't need to track/join threads
            t.start()  # start the thread, this is non-blocking
person zwer    schedule 27.06.2017
comment
спасибо @zwer позвольте мне оценить это, и я вернусь к вам - person nskalis; 27.06.2017