Tornado中gen.coroutine详解
1.gen.coroutine的作用
自动执行生成器
2.Future对象
在介绍异步使用之前,先了解一下Future对象的作用。
Future简单可以理解为一个占位符,将来会执行的对象,类似javascript中的promise对象,是实现异步的关键。
class Future(object):
    def __init__(self):
        self._callback = []
        self._result = None
        self._done = False
    def set_callback(self, cb):
        self._callback.append(cb)
    def _run_callback(self):
        for cb in self._callback:
            cb()
    def set_result(self, result)
        self._done = True
        self._result = result
        self._run_callback()
    def is_ready(self):
        return self._done is True
_result:返回结果值
_done:是否完成
_callback:完成后,执行的回调列表
set_result():赋值result,Future对象完成,执行回调。
3.callback实现异步
from tornado.httpclient import AsyncHTTPClient
from tornado.web import RequestHandler
class Test1Handler(RequestHandler):
    def get(self, *args, **kwargs):
        http_client = AsyncHTTPClient()
        http_client.fetch('www.baidu.com', callback = self.on_fetched)
        print('done')
    def on_fetched(self, response):
        print('response')
运行结果:

源码分析:
def fetch(self, request, callback=None, raise_error=True, **kwargs):
    if callback is not None:
        def handle_future(future):
            response = future.result()
            self.io_loop.add_callback(callback, response)
        future.add_done_callback(handle_future)
    def handle_response(response):
        if raise_error and response.error:
            future.set_exception(response.error)
        else:
            future.set_result(response)
	self.fetch_impl(request, handle_response)
    return future	
def fetch_impl(self, request, callback):
    raise NotImplementedError()
fetch函数返回一个Future类型对象,fetch_impl()执行完毕,返回结果response作为参数,执行回调handle_response
handle_response将response赋值给future。future状态变为已完成,执行future的callback函数handle_future,handle_future将callback加入ioloop执行队列,response作为参数。
由ioloop调度完成callback。
关键点在于,Future占位符控制了什么时候执行回调。
3.gen.coroutine实现异步
from tornado.httpclient import AsyncHTTPClient
from tornado.web import RequestHandler
from tornado import gen
class Test1Handler(RequestHandler):
    @gen.coroutine
    def get(self, *args, **kwargs):
        http_client = AsyncHTTPClient()
        response = yield http_client.fetch('http://www.baidu.com')
        print('response')
运行结果:

当执行到yield 表达式时,表达式会返回一个Future占位符,然后返回,当表达式执行完毕后,自动继续执行生成器。
关键点在于,gen.coroutine使生成器可以自动执行。
源码分析:
def coroutine(func, replace_callback=True):
	return _make_coroutine_wrapper(func, replace_callback=True)
def _make_coroutine_wrapper(func, replace_callback):
	try:
	    yielded = next(result)
	except (StopIteration, Return) as e:
	    future.set_result(getattr(e, 'value', None))
	except Exception:
	    future.set_exc_info(sys.exc_info())
	else:
	    Runner(result, future, yielded)
result:生成器对象
yielded:Future对象,生成器首次执行结果,如果异常StopIteration,表示生成器执行完毕,将结果设置成future的值,返回,装饰器gen.coroutine返回的为Future对象。
Runner:判断yielded是否完成,完成则执行run函数,继续执行生成器;否则,添加run函数到这个Future对象yielded,执行完毕之后,才调用run函数。
class Runner(object):
	def __init__(self, gen, result_future, first_yielded):
        if self.handle_yield(first_yielded):
            gen = result_future = first_yielded = None
            self.run()
	def handle_yield(self, yielded):
	    self.future = convert_yielded(yielded)
	    if not self.future.done() or self.future is moment:
	        self.io_loop.add_future(
	            self.future, lambda f: self.run())
	        return False
	    return True
	def run(self):
        if self.running or self.finished:
            return
        try:
            self.running = True
            while True:
                future = self.future
                if not future.done(): #执行run时generator返回的那个future必须已经有结果,否则就没必要传回到generator中了
                    return
                self.future = None
                try:
                    value = future.result()
                    yielded = self.gen.send(value)
                except (StopIteration, Return) as e:
                    #generator执行完毕并成功的处理
                except Exception:
                    #generator执行过程中异常的处理
                if not self.handle_yield(yielded):
                    return
        finally:
            self.running = False
handle_yield:判断Future对象yielded是否完成,未完成,注册run()函数回调到这个Future对象,完成,才调用。
run:将yielded这个Future对象的result,作为参数传递给生成器,继续执行生成器。
Tornado中gen.coroutine详解的更多相关文章
- Unity3D中的Coroutine详解
		
Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这样的代码. 疑问: yield是什么? Coroutine是什么? unity的coroutin ...
 - 【Unity3D/C#】Unity3D中的Coroutine详解
		
Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这样的代码. 疑问: yield是什么? Coroutine是什么? unity的coroutin ...
 - php中关于引用(&)详解
		
php中关于引用(&)详解 php的引用(就是在变量或者函数.对象等前面加上&符号) 在PHP 中引用的意思是:不同的变量名访问同一个变量内容. 与C语言中的指针是有差别的.C语言中的 ...
 - JavaScript正则表达式详解(二)JavaScript中正则表达式函数详解
		
二.JavaScript中正则表达式函数详解(exec, test, match, replace, search, split) 1.使用正则表达式的方法去匹配查找字符串 1.1. exec方法详解 ...
 - AngularJS select中ngOptions用法详解
		
AngularJS select中ngOptions用法详解 一.用法 ngOption针对不同类型的数据源有不同的用法,主要体现在数组和对象上. 数组: label for value in a ...
 - 【转载】C/C++中extern关键字详解
		
1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...
 - oracle中imp命令详解 .
		
转自http://www.cnblogs.com/songdavid/articles/2435439.html oracle中imp命令详解 Oracle的导入实用程序(Import utility ...
 - Android中Service(服务)详解
		
http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...
 - python中threading模块详解(一)
		
python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...
 
随机推荐
- mysql find_in_set
			
select * from IpResourceInfo a where find_in_set(a.id,(SELECT group_concat(CAST(resourcesid AS char) ...
 - Java容器集合类的区别用法
			
Set,List,Map,Vector,ArrayList的区别 JAVA的容器---List,Map,Set Collection ├List │├LinkedList │├ArrayList │└ ...
 - http状态--status[查询的资料备注]
			
HTTP 状态消息 当浏览器从 web 服务器请求服务时,可能会发生错误. 从而有可能会返回下面的一系列状态消息: 1xx: 信息 消息: 描述: 100 Continue 服务器仅接收到部分请求,但 ...
 - Elasticsearch报警插件Watch安装以及使用
			
参考:http://blog.csdn.net/ptmozhu/article/details/52296958 http://corejava2008.iteye.com/blog/2214279 ...
 - memcached全面剖析--5. memcached的应用和兼容程序
			
我是Mixi的长野.memcached的连载终于要结束了.到上次为止,我们介绍了与memcached直接相关的话题,本次介绍一些mixi的案例和实际应用上的话题,并介绍一些与memcached兼容的程 ...
 - apache配置中ProxyPassReverse指令的含义
			
apache中的mod_proxy模块主要作用就是进行url的转发,即具有代理的功能.应用此功能,可以很方便的实现同tomcat等应用服务器的整合,甚者可以很方便的实现web集群的功能. 例如使用ap ...
 - MySQL备份与还原详细过程示例
			
MySQL备份与还原详细过程示例 一.MySQL备份类型 1.热备份.温备份.冷备份 (根据服务器状态) 热备份:读.写不受影响: 温备份:仅可以执行读操作: 冷备份:离线备份:读.写操作均中止: 2 ...
 - 五年屌丝运维工作shell精华
			
屌丝运维常用shell列出你最常用的10条shellhistory | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | so ...
 - 重整ADO.NET连接池相关资料
			
https://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqlconnection.connectionstring(VS.80) ...
 - ASP.NET MVC3 Model验证总结 @Html.ValidationSummary(true)
			
http://www.wyjexplorer.cn/Post/2012/8/3/model-validation-in-aspnet-mvc3 ASP.NET MVC3中的Model是自验证的,这是通 ...