tornado调用ioloop TracebackFuture实现非堵塞的模块
转载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) 
 | 
                    
                
                
            
        
浙公网安备 33010602011771号