Python Tornado - немедленное возвращение POST, пока работает асинхронная функция - PullRequest
7 голосов
/ 06 октября 2010

поэтому у меня есть обработчик ниже:

class PublishHandler(BaseHandler):

    def post(self):
        message = self.get_argument("message")
        some_function(message)
        self.write("success")

Проблема, с которой я сталкиваюсь, заключается в том, что some_function () занимает некоторое время для выполнения, и я хотел бы, чтобы запрос post сразу возвращался при вызове, и чтобы some_function () выполнялась в другом потоке / процессе, если это возможно. 1004 *

Я использую Berkeley DB в качестве базы данных, и то, что я пытаюсь сделать, относительно просто.

У меня есть база данных пользователей, каждый с фильтром. Если фильтр соответствует сообщению, сервер отправит сообщение пользователю. В настоящее время я тестирую тысячи пользователей, и, следовательно, после каждой публикации сообщения с помощью почтового запроса он перебирает тысячи пользователей, чтобы найти совпадение. Это моя наивная реализация выполнения дел и, следовательно, мой вопрос. Как мне сделать это лучше?

Ответы [ 2 ]

7 голосов
/ 06 октября 2010

Вы можете сделать это, используя ваш IOLoop метод add_callback, например:

loop.add_callback(lambda: some_function(message))

Tornado выполнит обратный вызов в следующем проходе IOLoop, который может (мне нужно было бы разобраться в кишках Торнадо, чтобы узнать наверняка, или, в качестве альтернативы, проверить его), разрешить выполнение запроса до того кода исполняется.

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

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

Если вы идете по многопоточному маршруту, вы можете создать хороший модуль «async executor» с мьютексом, потоком и очередью. Проверьте модуль multiprocessing, если вы хотите пойти по пути использования отдельного процесса.

1 голос
/ 09 декабря 2010

Я пробовал это, и я полагаю, что запрос не завершается до вызова обратных вызовов.

Я думаю, что грязным хаком было бы вызвать два уровня add_callback, например:

  def get(self):
    ...
    def _defered():
      ioloop.add_callback(<whatever you want>)
    ioloop.add_callback(_defered)
    ...

Но в лучшем случае это хаки.Я ищу лучшее решение прямо сейчас, вероятно, в конечном итоге с какой-то очереди сообщений или простого потока решения.

...