tornado调用ioloop TracebackFuture实现非堵塞的模块

在国外论坛看到一个老外关于 tornado的一些非堵塞模块原理性的讲述,一刹那间明了了很多。 so 通过自己的理解,简单实现了下一个简单的非堵塞模块。  

嗯哼,原文地址是,blog.xiaorui.cc

当然实现的方法,还是存在点问题的, 但是最少流程是跑通了。 我在用ab做测试的时候,会发现数据已经进入到ioloop里面,但是逻辑堵塞到我们调用的函数上。 

下一步再写一个,tornado redis brpop的非堵塞模块。 

咱们先来看看,tornado的那个异步的装饰器@gen.coroutine,到底做了什么事情?

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来生成的。 

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()

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)


大家觉得文章对你有些作用! 如果想赏钱,可以用微信扫描下面的二维码,感谢!
另外再次标注博客原地址  xiaorui.cc

5 Responses

  1. ヽoo悾絔℅o。 2015年5月6日 / 上午9:54

    这个好像如果两次请求不同的sleep时间。首先请求sleep 6s。再请求sleep 2s。。。第二个请求还是堵塞了吧

  2. 你才 2015年3月5日 / 上午11:24

    ….

  3. 自由人 2015年1月28日 / 上午8:40

    请教下,是不是在tornado下任何逻辑逻辑都要改成非堵塞的?

  4. 自由人 2015年1月28日 / 上午8:39

    这个不错

发表评论

邮箱地址不会被公开。 必填项已用*标注