Python Tornado 非同步處理實現
阿新 • • 發佈:2018-12-18
本文將敘述如何利用執行緒池的方式實現Tornado的非同步處理。
1. 非同步處理方案
在處理請求應用上加上@tornado.web.asynchronous和@tornado.gen.engine裝飾器,即可實現非同步方法配合實現非阻塞請求處理。請求上加了這兩個裝飾器,@tornado.web.asynchronous裝飾器表明該請求不會自動斷掉輸出流,且需要顯式的呼叫finish方法。此外,asynchronous需要和@tornado.gen.engine搭配使用。
請求在沒有加上裝飾器@tornado.web.asynchronous時,get(post)方法結束後,請求會自動斷開,但是加上這個裝飾器後,get請求可以直接return且保持連線,直到顯式的呼叫finish方法才會關閉輸出流。即,在接受到請求後,get(post)方法直接交給別的函式來處理,處理完後再由get(post)方法呼叫finish()來關閉輸出流。
但是,當非同步處理函式裡有死迴圈導致get(post)處理函式阻塞,亦不能讓伺服器處理別的請求。因為Tornado是單執行緒事件驅動模式的伺服器,一旦方法阻塞,必然導致伺服器阻塞。不過,依然有辦法處理這種情況,那就是開啟多執行緒。
2. 非同步處理實現
#-*- coding:utf-8 -*- import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web import os.path import logging import time from tornado.concurrent import run_on_executor from concurrent.futures import ThreadPoolExecutor from tornado.options import define, options # 絕對路徑 tool_path = os.path.abspath(os.path.dirname(__file__)) # log config logging.basicConfig(level=logging.DEBUG,format="[%(asctime)s] %(levelname)s %(message)s", datefmt="%Y-%m-%d %H:%M:%S") #定義埠為8888 define("port", default=8888, help="run on the given port", type=int) # POST請求 class IndexHandler(tornado.web.RequestHandler): # 執行緒池 max_thread_num = 10 executor = ThreadPoolExecutor(max_workers=max_thread_num) # 執行緒內處理 @run_on_executor def my_func(self): # do your thing time.sleep(10) return 1 @tornado.web.asynchronous @tornado.gen.engine def post(self): res = yield self.my_func() self.write(str(res)) self.finish() def callback(): print("start web server process") # 主函式 def main(): tornado.options.parse_command_line() # 定義app app = tornado.web.Application( handlers=[(r'/test', IndexHandler)] ) http_server = tornado.httpserver.HTTPServer(app,callback()) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start() if __name__ == '__main__': main()
3. 非同步處理驗證
連續傳送請求兩次,判斷下該服務是否非同步處理請求。如果是單步處理,則兩條請求返回時間應該相差10s。如圖所示,兩條請求是幾乎同時處理完成的,說明非同步處理成功。