转载http://xiaorui.cc/2014/11/26/tornado调用ioloop-tracebackfuture实现非堵塞的模块/
当然实现的方法,还是存在点问题的, 但是最少流程是跑通了。 我在用ab做测试的时候,会发现数据已经进入到ioloop里面,但是逻辑堵塞到我们调用的函数上。
tornado.web.asynchronous
的作用是保持长连接,也就是除非你主动调用self.finish()
方法,否则requestHandler
将不会返回。
tornado.gen.coroutine
是使用协程的方式实现类似异步的处理效果。最新版的tornado,其实不一定需要写
下一步再写一个,tornado redis brpop的非堵塞模块。
咱们先来看看,tornado的那个异步的装饰器@gen.coroutine,到底做了什么事情?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | def _make_coroutine_wrapper(func, replace_callback): @functools.wraps(func) def wrapper(*args, **kwargs): runner = None future = TracebackFuture() #创建了一个新的Future对象,这货就是Future. if replace_callback and 'callback' in kwargs: callback = kwargs.pop('callback') IOLoop.current().add_future( future, lambda future: callback(future.result())) #当future执行完就把callback加入ioloop. try: result = func(*args, **kwargs) #调用被装饰函数 except (Return, StopIteration) as e: result = getattr(e, 'value', None) except Exception: future.set_exc_info(sys.exc_info()) return future else: if isinstance(result, types.GeneratorType): #如果被装饰函数被调用后产生一个Generator就用一个Runner来让future调用result. runner = Runner(result, future) runner.run() return future future.set_result(result) return future return wrapper |
这个是tornado的demo,异步的逻辑需要你用yield async来生成的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | import tornado.ioloop import tornado.web from tornado.gen import coroutine import torasync import time def test(a): time.sleep(3) print 'coming' return 'ok' class MainHandler(tornado.web.RequestHandler): @coroutine def get(self): result = yield tornasync.async(test, "xiaorui.cc") self.write("%s" % result ) application = tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | from tornado.concurrent import TracebackFuture from tornado.ioloop import IOLoop def async(task, *args, **kwargs): callback = kwargs.pop("callback", None) if callback: IOLoop.instance().add_future(future, lambda future: callback(future.result())) result = task(*args,**kwargs) IOLoop.instance().add_callback(_on_result, result, future) return future def _on_result(result, future): # if result is not ready, add callback function to next loop, if result: future.set_result(result) else: IOLoop.instance().add_callback(_on_result, result, future) |