1. 程式人生 > >Python Tornado 非同步處理實現

Python Tornado 非同步處理實現

本文將敘述如何利用執行緒池的方式實現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。如圖所示,兩條請求是幾乎同時處理完成的,說明非同步處理成功。