Python Tornado - 实现POST立即返回,异步函数继续执行
我有一个处理程序,如下所示:
class PublishHandler(BaseHandler):
def post(self):
message = self.get_argument("message")
some_function(message)
self.write("success")
我遇到的问题是,some_function()这个函数执行起来需要一些时间。我希望在调用这个POST请求时,能够立即返回,而不是等这个函数执行完再返回。如果可以的话,我想让some_function()在另一个线程或进程中执行。
我使用的是berkeley db作为数据库,我想做的事情相对简单。
我有一个用户数据库,每个用户都有一个过滤器。如果过滤器匹配了消息,服务器就会把消息发送给这个用户。目前我在测试成千上万的用户,因此每次通过POST请求发布消息时,服务器都要遍历成千上万的用户来寻找匹配。这是我比较简单的实现方式,所以我想问,怎样才能做得更好呢?
2 个回答
我试过这个,我觉得在回调函数被调用之前,请求并没有完成。
我觉得一个不太好的解决办法是调用两层的add_callback,比如:
def get(self):
...
def _defered():
ioloop.add_callback(<whatever you want>)
ioloop.add_callback(_defered)
...
不过这些方法充其量也只是权宜之计。我现在在寻找更好的解决方案,可能最后会用到消息队列或者简单的线程解决方案。
你可以试着用你的 IOLoop
的 add_callback
方法来实现这个功能,像这样:
loop.add_callback(lambda: some_function(message))
Tornado 会在下一个 IOLoop 的循环中执行这个回调,这样可能会让请求在执行这段代码之前完成(我得深入研究 Tornado 的内部机制才能确定,或者直接测试一下)。
不过,这样的缺点是你写的那段耗时的代码还是需要时间来执行,这可能会阻塞其他请求。如果同时有很多请求进来,这就不太好了。
更稳妥的解决办法是把它放在一个单独的线程或进程中运行。对于 Python 来说,使用进程是最好的选择,因为有个叫 GIL 的东西(如果你不太了解这个,建议你查一下)。不过,如果你是在单核处理器的机器上,使用线程也能正常工作,而且可能更简单。
如果你选择使用线程,可以构建一个不错的“异步执行器”模块,里面包含一个互斥锁、一个线程和一个队列。如果你想用单独的进程,可以看看 multiprocessing
模块。