一個開源分佈式博客blog_xtg的分析

原文地址:https://github.com/xtg20121013/blog_xtg

閱讀知識點準備:

tornadis用法

concurrent.futures.ThreadPoolExecutor任務用法

orm的用法-sqlalchemy的用法

apscheduler的TornadoScheduler的用法

 

main.py裏面依次做了三件事:

tornado的application的加入

redis訂閱加入

TornadoScheduler的加入

這三個異步任務都加入到tornado的loop循環中了

TornadoScheduler 負責刷新所有緩存,從數據庫重建緩存並通知其他節點,用於定時任務校準緩存,通過yield tornadis.call來完成任務的;返回方式是raise tornado.gen.Return(reply)

查詢數據的時候還涉及了其他方式的使用異步blog_info = yield thread_do(BlogInfoService.get_blog_info, db),這個和路由裏面的handler的處理方法是一樣的(tornado的application),例如pager = yield self.async_do(ArticleService.page_articles, self.db, pager, article_search_params)

thread_do和async_do實際上都是concurrent.futures.ThreadPoolExecutor.submit,

這個線程池做的操作基本上是sqlalchemy的操作,比如add_comment這種純存保存到數據庫的操作:

comment_to_add = Comment(content=comment['content'], author_name=comment['author_name'],
                         author_email=comment['author_email'], article_id=article_id,
                         comment_type=comment['comment_type'], rank=comment['rank'], floor=floor,
                         reply_to_id=comment['reply_to_id'], reply_to_floor=comment['reply_to_floor'])
db_session.add(comment_to_add)
db_session.commit()

,或者query = db_session.query(Article)這種從數據庫裏面查詢數據返回對象的操作,這兩個都是同步操作

但是這個submit和coroutine交叉使用就讓人迷糊了,怎麼做到的呢。

class ThreadPoolExecutor(_base.Executor):
def submit(self, fn, *args, **kwargs):
    with self._shutdown_lock:
        if self._shutdown:
            raise RuntimeError('cannot schedule new futures after shutdown')

        f = _base.Future()
        w = _WorkItem(f, fn, args, kwargs)

        self._work_queue.put(w)
        self._adjust_thread_count()
        return f

猜測submit操作會交出原來的協程的使用權,等到子線程把這種耗時的操作完成之後,來通知原來線程的事件循環,原來協程完成了,可以往下運行了.

繼續分析:submit及時返回一個future可以讓事件循環知道,但是查詢狀態是未完成的,就先調度其他的協程;future變量可以跨線程的,所以一旦子線程完成是可以修改結果和狀態(done),事件循環運行到這個協程再通過get_result傳遞實際的值

這裏面有個重要的概念,result = yield future,左邊並不是直接得到的是future,而是先不斷向上傳出生成器,直到傳到事件循環,事件循環檢查future對象狀態,通過send future的結果即f.result()不斷向下直到等號右邊變量:

loop——yield——>f3——yield——>f2——yield——>f1——yield——>future(yield 只負責傳出生成器,再次調用生成器f3.send(None),f1.send(something),something才被傳遞到等號左邊的result

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章