亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

tornado異步請求非阻塞

2019-11-14 17:52:00
字體:
來源:轉載
供稿:網友

前言

也許有同學很迷惑:tornado不是標榜異步非阻塞解決10K問題的嘛?但是我卻發現不是torando不好,而是你用錯了.比如最近發現一個事情:某網站打開頁面很慢,服務器cpu/內存都正常.網絡狀態也良好. 后來發現,打開頁面會有很多請求后端數據庫的訪問,有一個mongodb的數據庫業務api的rest服務.但是它的tornado卻用錯了,一步步的來研究問題:

說明

以下的例子都有2個url,一個是耗時的請求,一個是可以或者說需要立刻返回的請求,我想就算一個對技術不熟,從道理上來說的用戶, 他希望的是他訪問的請求不會影響也不會被其他人的請求影響

#!/bin/env pythonimport tornado.httpserverimport tornado.ioloopimport tornado.optionsimport tornado.webimport tornado.httpclientimport timefrom tornado.options import define, optionsdefine("port", default=8000, help="run on the given port", type=int)class SleepHandler(tornado.web.RequestHandler):    def get(self):        time.sleep(5)        self.write("when i sleep 5s")class JustNowHandler(tornado.web.RequestHandler):    def get(self):        self.write("i hope just now see you")if __name__ == "__main__":    tornado.options.parse_command_line()    app = tornado.web.application(handlers=[            (r"/sleep", SleepHandler), (r"/justnow", JustNowHandler)])    http_server = tornado.httpserver.HTTPServer(app)    http_server.listen(options.port)    tornado.ioloop.IOLoop.instance().start()

假如你使用頁面請求或者使用哪個httpie,curl等工具先訪問http://localhost:8000/sleep,再訪問http://localhost:8000/justnow.你會發現本來可以立刻返回的/jsutnow的請求會一直阻塞到/sleep請求完才返回.

這是為啥?為啥我的請求被/sleep請求阻塞了?如果平時我們的web請求足夠快我們可能不會意識到這個問題,但是事實上經常會有一些耗時的進程,意味著應用程序被有效的鎖定直至處理結束.

這是時候你有沒有想起@tornado.web.asynchronous這個裝飾器?但是使用這個裝飾器有個前提就是你要耗時的執行需要執行異步,比如上面的time.sleep,你只是加裝飾器是沒有作用的,而且需要注意的是 Tornado默認在函數處理返回時關閉客戶端的連接,但是當你使用@tornado.web.asynchonous裝飾器時,Tornado永遠不會自己關閉連接,需要顯式的self.finish()關閉

我們大部分的函數都是阻塞的, 比如上面的time.sleep其實tornado有個異步的實現:

#!/bin/env pythonimport tornado.httpserverimport tornado.ioloopimport tornado.optionsimport tornado.webimport tornado.genimport tornado.httpclientimport tornado.concurrentimport tornado.ioloopimport timefrom tornado.options import define, optionsdefine("port", default=8000, help="run on the given port", type=int)class SleepHandler(tornado.web.RequestHandler):    @tornado.web.asynchronous    @tornado.gen.coroutine    def get(self):        yield tornado.gen.Task(tornado.ioloop.IOLoop.instance().add_timeout, time.time() + 5)        self.write("when i sleep 5s")class JustNowHandler(tornado.web.RequestHandler):    def get(self):        self.write("i hope just now see you")if __name__ == "__main__":    tornado.options.parse_command_line()    app = tornado.web.Application(handlers=[            (r"/sleep", SleepHandler), (r"/justnow", JustNowHandler)])    http_server = tornado.httpserver.HTTPServer(app)    http_server.listen(options.port)    tornado.ioloop.IOLoop.instance().start()

這里有個新的tornado.gen.coroutine裝飾器, coroutine是3.0之后新增的裝飾器.以前的辦法是用回調,還是看我這個例子:

class SleepHandler(tornado.web.RequestHandler):    @tornado.web.asynchronous    def get(self):        tornado.ioloop.IOLoop.instance().add_timeout(time.time() + 5, callback=self.on_response)    def on_response(self):        self.write("when i sleep 5s")        self.finish()

使用了callback, 但是新的裝飾器讓我們通過yield實現同樣的效果:你在打開/sleep之后再點擊/justnow, justnow的請求都是立刻返回不受影響.但是用了asynchronous的裝飾器你的耗時的函數也需要執行異步

剛才說的都是沒有意義的例子,下面寫個有點用的:讀取mongodb數據庫數據,然后再前端按行write出來

#!/bin/env pythonimport tornado.httpserverimport tornado.ioloopimport tornado.optionsimport tornado.webimport tornado.genimport tornado.httpclientimport tornado.concurrentimport tornado.ioloopimport time# 一個mongodb出品的支持異步的數據庫的python驅動import motorfrom tornado.options import define, optionsdefine("port", default=8000, help="run on the given port", type=int)# db其實就是test數據庫的游標db = motor.MotorClient().open_sync().testclass SleepHandler(BaseHandler):    @tornado.web.asynchronous    @tornado.gen.coroutine    def get(self):        # 這一行執行還是阻塞需要時間的,我的tt集合有一些數據并且沒有索引        cursor = db.tt.find().sort([('a', -1)])        # 這部分會異步非阻塞的執行二不影響其他頁面請求        while (yield cursor.fetch_next):            message = cursor.next_object()            self.write('<li>%s</li>' % message['a'])        self.write('</ul>')        self.finish()    def _on_response(self, message, error):        if error:            raise tornado.web.HTTPError(500, error)        elif message:            for i in message:                self.write('<li>%s</li>' % i['a'])        else:            self.write('</ul>')            self.finish()class JustNowHandler(BaseHandler):    def get(self):        self.write("i hope just now see you")if __name__ == "__main__":    tornado.options.parse_command_line()    app = tornado.web.Application(handlers=[            (r"/sleep", SleepHandler), (r"/justnow", JustNowHandler)])    http_server = tornado.httpserver.HTTPServer(app)    http_server.listen(options.port)    tornado.ioloop.IOLoop.instance().start()

一個同事提示為什么這個耗時的東西不能異步的丟給某工具去執行而不阻塞我的請求呢?好吧,我也想到了:celery,正好github有這個東西:tornado-celery

執行下面的程序首先你要安裝rabbitmq和celery:

#!/bin/env pythonimport tornado.httpserverimport tornado.ioloopimport tornado.optionsimport tornado.webimport tornado.genimport tornado.httpclientimport tcelery, tasksimport timefrom tornado.options import define, optionsdefine("port", default=8000, help="run on the given port", type=int)tcelery.setup_nonblocking_PRoducer()class SleepHandler(tornado.web.RequestHandler):    @tornado.web.asynchronous    @tornado.gen.coroutine    def get(self):        # tornado.gen.Task的參數是:要執行的函數, 參數        yield tornado.gen.Task(tasks.sleep.apply_async, args=[5])        self.write("when i sleep 5s")        self.finish()class JustNowHandler(tornado.web.RequestHandler):    def get(self):        self.write("i hope just now see you")if __name__ == "__main__":    tornado.options.parse_command_line()    app = tornado.web.Application(handlers=[            (r"/sleep", SleepHandler), (r"/justnow", JustNowHandler)])    http_server = tornado.httpserver.HTTPServer(app)    http_server.listen(options.port)    tornado.ioloop.IOLoop.instance().start()

task是celery的任務定義的文件,包含我們說的time.sleep的函數

import timefrom celery import Celerycelery = Celery("tasks", broker="amqp://guest:guest@localhost:5672")celery.conf.CELERY_RESULT_BACKEND = "amqp"@celery.taskdef sleep(seconds):    time.sleep(float(seconds))    return secondsif __name__ == "__main__":    celery.start()

然后啟動celelry worker(要不然你的任務怎么執行呢?肯定需要一個消費者取走):

celery -A tasks worker --loglevel=info

但是這里的問題也可能很嚴重:我們的異步非阻塞依賴于celery,還是這個隊列的長度,假如任務很多那么就需要等待,效率很低.有沒有一種辦法把我的同步阻塞函數變為異步(或者說被tornado的裝飾器理解和識別)呢?

#!/bin/env pythonimport tornado.httpserverimport tornado.ioloopimport tornado.optionsimport tornado.webimport tornado.httpclientimport tornado.genfrom tornado.concurrent import run_on_executor# 這個并發庫在python3自帶在python2需要安裝sudo pip install futuresfrom concurrent.futures import ThreadPoolExecutorimport timefrom tornado.options import define, optionsdefine("port", default=8000, help="run on the given port", type=int)class SleepHandler(tornado.web.RequestHandler):    executor = ThreadPoolExecutor(2)  #executor 是局部變量  不是全局的
@tornado.web.asynchronous @tornado.gen.coroutine def get(self): # 假如你執行的異步會返回值被繼續調用可以這樣(只是為了演示),否則直接yield就行 res = yield self.sleep() self.write("when i sleep %s s" % res) self.finish() @run_on_executor def sleep(self): time.sleep(5) return 5class JustNowHandler(tornado.web.RequestHandler): def get(self): self.write("i hope just now see you")if __name__ == "__main__": tornado.options.parse_command_line() app = tornado.web.Application(handlers=[ (r"/sleep", SleepHandler), (r"/justnow", JustNowHandler)]) http_server = tornado.httpserver.HTTPServer(app) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()
本文轉載自http://www.dongwm.com/archives/shi-yong-tornadorang-ni-de-qing-qiu-yi-bu-fei-zu-sai/

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
97精品久久久中文字幕免费| 亚洲免费成人av电影| 色天天综合狠狠色| 日韩av一区二区在线观看| 欧美巨猛xxxx猛交黑人97人| 国产精品无码专区在线观看| 国内精品久久久久久久| 欧美性视频网站| 国产mv免费观看入口亚洲| 亚洲人成欧美中文字幕| 日韩欧美在线视频免费观看| 精品国产乱码久久久久久天美| 国产亚洲欧美日韩美女| 欧美大片在线影院| 国产成人精品视| 高清欧美性猛交| 日韩在线播放一区| 国产精品久久久久久久久久久新郎| 欧美午夜片欧美片在线观看| 久久亚洲精品小早川怜子66| 日韩在线视频免费观看| 亚洲成人av片在线观看| 欧美精品久久久久a| 日日噜噜噜夜夜爽亚洲精品| 亚洲人成网站色ww在线| 久久久久久网站| 色琪琪综合男人的天堂aⅴ视频| 国产亚洲精品激情久久| 国产91网红主播在线观看| 69av视频在线播放| 日韩亚洲成人av在线| 精品久久久久久久久久久| 亚洲第一网中文字幕| 不卡av在线网站| 日韩欧美在线第一页| 日韩av手机在线观看| 亚洲精品成人久久电影| 国产精品高潮视频| 欧美一区二区大胆人体摄影专业网站| 国产91精品久久久久| 久久夜精品香蕉| 精品偷拍一区二区三区在线看| 理论片在线不卡免费观看| 日韩精品中文字幕视频在线| 国产精品99导航| 亚洲午夜未满十八勿入免费观看全集| 亚洲福利视频网| 精品国产欧美一区二区三区成人| 91av在线播放视频| www.欧美精品一二三区| 色综合导航网站| 欧美肥臀大乳一区二区免费视频| 成人国产精品久久久久久亚洲| 欧美色视频日本高清在线观看| 57pao国产精品一区| 亚洲欧洲在线播放| 午夜精品久久久久久久久久久久| 亚洲嫩模很污视频| 亚洲成年人在线播放| 日韩最新av在线| 亚洲欧美福利视频| 欧美精品精品精品精品免费| 欧美一级bbbbb性bbbb喷潮片| 夜夜嗨av色一区二区不卡| 91中文字幕在线| 国产成人在线播放| 日韩高清不卡av| 亚洲精品v欧美精品v日韩精品| 97在线观看视频国产| 国产成人中文字幕| 大荫蒂欧美视频另类xxxx| 精品人伦一区二区三区蜜桃免费| 日韩av片免费在线观看| 欧美巨大黑人极品精男| 欧美极品少妇xxxxⅹ喷水| 国产精品7m视频| 欧美黑人狂野猛交老妇| 91精品视频在线| 国产精品自产拍高潮在线观看| 国产精品视频网站| 亚洲资源在线看| 亚洲欧美激情视频| 成人在线国产精品| 亚洲色图色老头| 日韩在线精品一区| 国产成人亚洲综合青青| 午夜欧美大片免费观看| 国产亚洲激情视频在线| 亚洲国产成人91精品| 亚洲精品久久久久| 欧美精品激情在线观看| 热99精品只有里视频精品| 亚洲天堂2020| 亚洲伊人一本大道中文字幕| 色综合男人天堂| 亚洲黄色在线观看| 欧美激情中文网| 日韩电影在线观看中文字幕| 亚洲色图综合网| 91国产高清在线| 国产精品久久久久久久久免费看| 国产成人综合亚洲| 欧美日韩国产一区在线| 欧美午夜www高清视频| 国产日产亚洲精品| 国产精品青草久久久久福利99| 欧美成人在线免费视频| 少妇精69xxtheporn| 亚洲免费小视频| 久久久成人的性感天堂| 久久久999国产精品| 欧美国产高跟鞋裸体秀xxxhd| 热99久久精品| 亚洲欧美激情四射在线日| 欧美最猛性xxxxx亚洲精品| 亚洲免费视频在线观看| 国产专区精品视频| 久久91亚洲精品中文字幕| 欧美乱人伦中文字幕在线| 久久精品99国产精品酒店日本| …久久精品99久久香蕉国产| 亚洲美女av在线播放| 成人xxxx视频| 欧美性猛交xxxx黑人猛交| 综合136福利视频在线| 永久免费看mv网站入口亚洲| 国产精品一区=区| 久久久久免费视频| 日韩在线视频一区| 国产精品丝袜久久久久久不卡| 国产精品av在线播放| 中文国产成人精品| 日韩小视频在线| 亚洲一区二区三区sesese| 国产成人精品在线观看| 欧美日韩aaaa| 欧美在线不卡区| 91精品国产色综合久久不卡98| 国内外成人免费激情在线视频网站| 国产伦精品一区二区三区精品视频| 欧美综合一区第一页| 亚洲精品电影久久久| 国产精品网红直播| 欧美亚洲在线视频| 亚洲色图在线观看| 日本精品免费一区二区三区| 久久久噜噜噜久噜久久| 91在线直播亚洲| 久久综合久久88| 久久成人人人人精品欧| 亚洲欧美国产精品| 福利视频导航一区| 欧美成人亚洲成人日韩成人| 91精品国产99| 国产精品盗摄久久久| 日韩免费电影在线观看| 亚洲精品黄网在线观看| 久久久999国产| 久久在线观看视频| 日韩黄色av网站| 国产精品吴梦梦| 亚洲精品98久久久久久中文字幕| 97在线精品国自产拍中文| 亚洲国产精品999|