摘要:一年多前的文章這次重新讀,再加上一些中給我的知識(shí),有了更深的理解。
一年多前的文章 http://segmentfault.com/a/1190000000426460 這次重新讀,再加上一些 js 中 co給我的知識(shí),有了更深的理解。
Front Knowledgeyield and generator will be the front knowledge of this article. And you should also have some sense of epoll/kqueue and callback style. Let"s enjoy the source code of the implement of coroutine.
Python TornadoA simple async fetch function used by a coroutine in Python, exception handle removed
def fetch(self, request): future = TracebackFuture() # TracebackFuture == Future def handle_response(response): future.set_result(response) self.fetch_impl(request, handle_response) # This is a async function return future def fetch_impl(self, request, callback): pass
future -- an instance of Future -- is an object that used to collect and send result to generator.
A coroutine that uses above fetch
@gen.coroutine def request(self, uri): response = yield http.fetch(uri)
And we all know @gen.coroutine is a syntax sugar of
request = gen.coroutine(request)
coroutine wrapper function, also exception handle removed
def _make_coroutine_wrapper(func, replace_callback): @functools.wraps(func) def wrapper(*args, **kwargs): future = TracebackFuture() try: result = func(*args, **kwargs) # result is a generator if the function is a generator function except (Return, StopIteration) as e: result = getattr(e, "value", None) else: if isinstance(result, types.GeneratorType): # if the function is a generator function try: yielded = next(result) # generator.next() will run the code above and right hand of the generator, for our example request here, http.fetch(uri) will run and return yielded(a instance of Future). except (StopIteration, Return) as e: future.set_result(getattr(e, "value", None)) else: Runner(gen=result, result_future=future, first_yielded=yielded) # Runner is like the co lib in Js written by TJ, Runner use a While True rather than recursive, because recursive is slower in Python. return future else: # or the function is jsut a normal function pass future.set_result(result) return future return wrapper
With the Tornado usage we can learn that the function after yield can be either a coroutine or a normal function.
Both of them returns a Future. You can write return Future by yourself or use @coroutine. But make sure your normal function is an async function.
Runner.run function, exception handle removed
def __init__(self, gen, result_future, first_yielded): # init of Runner ... # some attrs bind self.future = first_yielded # removed some complex logic, just show the basic logic of running the `request` generator. self.io_loop.add_future( self.future, lambda f: self.run()) # io_loop is a epoll based loop, the second function is a callback function when future is finished. def run(self): """Starts or resumes the generator, running until it reaches a yield point that is not ready. """ while True: if not future.done(): return try: value = future.result() yielded = self.gen.send(value) except (StopIteration, Return) as e: self.finished = True return except Exception: self.finished = True return if not self.handle_yield(yielded): return
Runner is like the co lib in Js written by TJ, Runner use a While True rather than recursive, because recursive is slower in Python. Both of them do the same thing, that is executing the generator unitl it"s done.
First of all, Runner add the future, or we can say the async function fetch to io_loop. If fetch is finish, itself will invoke the callback function handle_response to set data to future. And the io_loop will invoke another callback function lambda f: self.run() to run the function run to get the result from future by value = future.result() and send to the generator by yield = gen.send(value) and start the next block of the generator function if exists until the whole function is stoped and return a StopIteration.
So let us figure out the effect of each object:
generator function: a function with yield statement
generator: invoke a generator function will return a generator
coroutine: a wrapper function to wrapper a generator function. It will create a runner to run the generator.
Future: used to collect and get result, it"s a result container.
Runner: it will register the future to io_loop and send result back to generator, and repeats unitl generator is done.
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/37715.html
摘要:序言最近閑暇無(wú)事閱讀了一下的源碼對(duì)整體的結(jié)構(gòu)有了初步認(rèn)識(shí)與大家分享不知道為什么右邊的目錄一直出不來(lái)非常不舒服不如移步到吧是的核心模塊也是個(gè)調(diào)度模塊各種異步事件都是由他調(diào)度的所以必須弄清他的執(zhí)行邏輯源碼分析而的核心部分則是這個(gè)循環(huán)內(nèi)部的邏輯貼 序言 最近閑暇無(wú)事,閱讀了一下tornado的源碼,對(duì)整體的結(jié)構(gòu)有了初步認(rèn)識(shí),與大家分享 不知道為什么右邊的目錄一直出不來(lái),非常不舒服. 不如移...
摘要:清楚了以上流程,我們直接來(lái)看函數(shù)主要用作初始化應(yīng)用監(jiān)聽(tīng)端口以及啟動(dòng)。其中就是保存聊天室所有聊天消息的結(jié)構(gòu)。關(guān)于的解讀我會(huì)放到閱讀源碼時(shí)講。然后把消息加到緩存里,如果緩存大于限制則取最新的條消息。 tornado 源碼自帶了豐富的 demo ,這篇文章主要分析 demo 中的聊天室應(yīng)用: chatdemo 首先看 chatdemo 的目錄結(jié)構(gòu): ├── chatdemo.py ├── ...
這篇文章摘自我的博客, 歡迎大家沒(méi)事去逛逛~ 背景 這幾個(gè)月我開(kāi)發(fā)了公司里的一個(gè)restful webservice,起初技術(shù)選型的時(shí)候是采用了flask框架。雖然flask是一個(gè)同步的框架,但是可以配合gevent或者其它方式運(yùn)行在異步的容器中(測(cè)試鏈接),效果看上去也還可以,因此就采用了這種方式。 后面閱讀了tornado的源碼,也去了解了各種協(xié)程框架以及運(yùn)行的原理??偢杏X(jué)flask的這種同步...
這篇文章摘自我的博客, 歡迎大家沒(méi)事去逛逛~ 背景 這幾個(gè)月我開(kāi)發(fā)了公司里的一個(gè)restful webservice,起初技術(shù)選型的時(shí)候是采用了flask框架。雖然flask是一個(gè)同步的框架,但是可以配合gevent或者其它方式運(yùn)行在異步的容器中(測(cè)試鏈接),效果看上去也還可以,因此就采用了這種方式。 后面閱讀了tornado的源碼,也去了解了各種協(xié)程框架以及運(yùn)行的原理??偢杏X(jué)flask的這種同步...
摘要:上一篇文章第一章異步及協(xié)程基礎(chǔ)第二節(jié)關(guān)鍵字下一篇文章第二章實(shí)戰(zhàn)演練開(kāi)發(fā)網(wǎng)站第一節(jié)網(wǎng)站結(jié)構(gòu)使用協(xié)程可以開(kāi)發(fā)出類(lèi)似同步代碼的異步行為。協(xié)程函數(shù)可以通過(guò)以下三張方式調(diào)用在本身是協(xié)程的函數(shù)內(nèi)通過(guò)關(guān)鍵字調(diào)用。 上一篇文章:Python:Tornado 第一章:異步及協(xié)程基礎(chǔ):第二節(jié):Python關(guān)鍵字yield下一篇文章:Python:Tornado 第二章:實(shí)戰(zhàn)演練:開(kāi)發(fā)Tornado網(wǎng)站:第...
閱讀 2141·2023-04-25 17:23
閱讀 2949·2021-11-17 09:33
閱讀 2551·2021-08-21 14:09
閱讀 3669·2019-08-30 15:56
閱讀 2634·2019-08-30 15:54
閱讀 1651·2019-08-30 15:53
閱讀 2160·2019-08-29 13:53
閱讀 1174·2019-08-29 12:31