性能:异步请求处理程序,具有由工作池处理的阻塞任务

时间:2013-01-13 17:52:23

标签: python asynchronous tornado

此脚本的效果如何:http://tornadogists.org/2185380/复制如下。

from time import sleep
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.web import Application, asynchronous, RequestHandler
from multiprocessing.pool import ThreadPool

_workers = ThreadPool(10)

def run_background(func, callback, args=(), kwds={}):
    def _callback(result):
        IOLoop.instance().add_callback(lambda: callback(result))
    _workers.apply_async(func, args, kwds, _callback)

# blocking task like querying to MySQL
def blocking_task(n):
    sleep(n)
    return n

class Handler(RequestHandler):
    @asynchronous
    def get(self):
        run_background(blocking_task, self.on_complete, (10,))

    def on_complete(self, res):
        self.write("Test {0}<br/>".format(res))
        self.finish()

HTTPServer(Application([("/", Handler)],debug=True)).listen(8888)
IOLoop.instance().start()
  1. 我的申请将超过 1,000 req / sec
  2. 每个请求将持续2-30秒,平均大约6秒
    • 只需平均sleep(6)
  3. 使用redis BLPOPQueue.get_nowait()
  4. 之类的内容来阻止IO

1 个答案:

答案 0 :(得分:2)

总体模式很好,但需要注意的是,由于GIL,您的线程池只能使用单个CPU,并且您需要使用多个进程来充分利用可用的硬件。 / p>

仔细看看这些数字,如果你的请求真的平均每个6秒,那么10个线程太小了。你每秒都有6000秒的工作量,所以你需要在所有进程中总共至少6000个线程(假设6秒实际上只是阻塞了外部事件和python进程中的CPU成本)可以忽略不计)。我不确定现代系统可以处理多少线程,但6000个Python线程听起来不是一个好主意。如果你真的有6秒的每个请求阻塞(以及数千个请求/秒),那么将这些阻塞函数转换为异步是合理的。