2010-10-06 2 views
6

поэтому у меня есть обработчик ниже:Python Tornado - сделать POST немедленно вернуться в то время как асинхронная функция продолжает работать

class PublishHandler(BaseHandler): 

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

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

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

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

ответ

7

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

loop.add_callback(lambda: some_function(message)) 

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

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

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

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

1

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

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

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

Но эти писаки в лучшем случае. Я ищу лучшее решение прямо сейчас, вероятно, закончится с некоторой очередью сообщений или простым решением потока.

Смежные вопросы