1.介紹
使用python編寫的網絡框架和高性能的異步網絡庫
使用大量連接、長輪詢、websockets應用
- 優勢:微服務、高性能、異步支持
- 缺點:輪子少不像Django、Flask等框架有大量插件支持;缺少最佳實踐,使用的公司不多,學習資料少
使用場景
構建微服務,不適合複雜的CMS(內容管理系統)應用;適合構建網站或者App後端微服務
學習資料
- 官方文檔:https://www.tornadoweb.org/en/stable/;
- github:https://github.com/tornadoweb/tornado
- 書:《Introduction to Tornado》
2.安裝和使用
安裝:pip install tornado
下載源碼學習示例代碼:git clone https://github.com/tornadoweb/tornado.git
(沒有git的話先安裝git,yum -y install git
)
官網上拷hello,word代碼
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
1.編寫一個hello world 應用 app.py,以上代碼
2.使用python app.py 啓動tornado應用
3.使用curl或者瀏覽器驗證:curl http://127.0.0.1:8888
3.Tornado web 主要模塊
主要模塊
tornado.web Application
和 RequestHandler
類處理http請求
tornado.template
模版渲染
tornado.routing
處理路由
HTTP服務器和客戶端模塊
tornado.httpserver
非阻塞HTTP客戶端
tornado.httpclient
異步HTTP客戶端
異步networking
tornado.ioloop
事件循環
tornado.iostream
非阻塞socket封裝
tornado.tcpserver
和 tornado.tcpclient
協程和併發
tornado.gen
協程模塊
tornado.locks/tornado.queues
同步、協程隊列模塊
4.三種啓動方式
app.listen()這個方法只能在單進程模式中使用。
對於app.listen()與方式二中的手動創建HTTPServer實例這兩種方式,建議大家先使用後者即創建HTTPServer實例的方式,因爲其對於理解tornado web應用工作流程的完整性有幫助,便於大家記憶tornado開發的模塊組成和程序結構;在熟練使用後,可以改爲簡寫。
第一種啓動方式:單進程
import tornado.web # web服務
import tornado.ioloop # I/O 時間循環
import tornado.httpserver # 新引入httpserver模塊,單線程的http服務
class Mainhandler(tornado.web.RequestHandler):
def get(self):
self.write("hello world!")
# 建立路由表
app = tornado.web.Application([
(r"/index", Mainhandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(8000)
# tornado.ioloop.IOLoop.current().start()
tornado.ioloop.IOLoop.instance().start() # 開始事件
在這一修改版本中,我們引入了tornado.httpserver模塊,顧名思義,它就是tornado的HTTP服務器實現。
我們創建了一個HTTP服務器實例http_server,因爲服務器要服務於我們剛剛建立的web應用,將接收到的客戶端請求通過web應用中的路由映射表引導到對應的handler中,所以在構建http_server對象的時候需要傳出web應用對象app。http_server.listen(8000)將服務器綁定到8000端口。
實際上一版代碼中app.listen(8000)正是對這一過程的簡寫。
第二種啓動方式:多進程
```python
import tornado.web # web服務
import tornado.ioloop # I/O 時間循環
import tornado.httpserver # 新引入httpserver模塊,單線程的http服務
class Mainhandler(tornado.web.RequestHandler):
def get(self):
self.write("hello world!")
# 建立路由表
app = tornado.web.Application([
(r"/index", Mainhandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(app)
http_server.bind(8000)
http_server.start(3)
# tornado.ioloop.IOLoop.current().start()
tornado.ioloop.IOLoop.instance().start() # 開始事件
http_server.bind(port)方法是將服務器綁定到指定端口。
http_server.start(num_processes=1)方法指定開啓幾個進程,參數num_processes默認值爲1,即默認僅開啓一個進程;如果num_processes爲None或者<=0,則自動根據機器硬件的cpu核芯數創建同等數目的子進程;如果num_processes>0,則創建num_processes個子進程。
前面寫的http_server.listen(8000)實際上就等同於:http_server.bind(8000) http_server.start(1)這兩行代碼。
第三種啓動方式:多進程
import tornado.web # web服務
import tornado.ioloop # I/O 時間循環
import tornado.httpserver # 新引入httpserver模塊,單線程的http服務
class Mainhandler(tornado.web.RequestHandler):
def get(self):
self.write("hello world!")
# 建立路由表
app = tornado.web.Application([
(r"/index", Mainhandler),
])
if __name__ == "__main__":
sockets = tornado.netutil.bind_sockets(8888)
tornado.process.fork_processes(0) # 10
http_server = tornado.httpserver.HTTPServer(app)
http_server.add_sockets(sockets)
# tornado.ioloop.IOLoop.current().start()
tornado.ioloop.IOLoop.instance().start() # 開始事件
我使用第三種方式部署服務
5.編寫高併發服務
get_data有方法裏面有多個數據接口,使用協程可以提高服務的併發能力
# -*-coding:utf8-*-
"""
-----
"""
import tornado.ioloop
import tornado.web
import tornado.httpserver
import tornado.options
from tornado.concurrent import run_on_executor
import http.client
from concurrent.futures import ThreadPoolExecutor
class MainHandler(tornado.web.RequestHandler):
executor = ThreadPoolExecutor(10) # 起線程池,由當前RequestHandler持有
@tornado.gen.coroutine
def get(self):
data = yield self.get_data(parameters)
@run_on_executor
def get_data(self, appId, userId, Client_parameters):
return data
class TestHandler(tornado.web.RequestHandler):
def get(self):
self.write('ok')
def make_app():
return tornado.web.Application([
(r"/", MainHandler), (r"/test", TestHandler)
])
if __name__ == "__main__":
app = make_app()
sockets = tornado.netutil.bind_sockets(8000)
tornado.process.fork_processes(0) # 10
http_server = tornado.httpserver.HTTPServer(app)
http_server.add_sockets(sockets)
tornado.ioloop.IOLoop.instance().start() # 開始事件