t2 初识Tornado
2.1 安裝
自動安裝 查看自己當前的環境是否已安裝 $ pip list 安裝 $ pip install tornado 手動安裝 下載安裝包tornado-4.3.tar.gz(https://pypi.python.org/packages/source/t/tornado/tornado-4.3.tar.gz) $ tar xvzf tornado-4.3.tar.gz $ cd tornado-4.3 $ python setup.py build $ sudo python setup.py install 關于使用平臺的說明 Tornado should run on any Unix-like platform, although for the best performance and scalability only Linux (with epoll) and BSD (with kqueue) are recommended for production deployment (even though Mac OS X is derived from BSD and supports kqueue, its networking performance is generally poor so it is recommended only for development use). Tornado will also run on Windows, although this configuration is not officially supported and is recommended only for development use.Tornado應該運行在類Unix平臺,在線上部署時為了最佳的性能和擴展性,僅推薦Linux和BSD(因為充分利用Linux的epoll工具和BSD的kqueue工具,是Tornado不依靠多進程/多線程而達到高性能的原因)。對于Mac OS X,雖然也是衍生自BSD并且支持kqueue,但是其網絡性能通常不太給力,因此僅推薦用于開發。對于Windows,Tornado官方沒有提供配置支持,但是也可以運行起來,不過僅推薦在開發中使用。 View Code?
2.2 hello tornado
新建文件hello.py,代碼如下:
# coding:utf-8import tornado.web import tornado.ioloopclass IndexHandler(tornado.web.RequestHandler):"""主路由處理類"""def get(self):"""對應http的get請求方式"""self.write("Hello tornado!")if __name__ == "__main__":app = tornado.web.Application([(r"/", IndexHandler),])app.listen(8000)tornado.ioloop.IOLoop.current().start()?
執行如下命令,開啟tornado:
$ python hello.py打開瀏覽器,輸入網址127.0.0.1:8000(或localhost:8000),查看效果:
?
代碼解釋
1. tornado.web
tornado的基礎web框架模塊
-
RequestHandler
封裝了對應一個請求的所有信息和方法,write(響應信息)就是寫響應信息的一個方法;對應每一種http請求方式(get、post等),把對應的處理邏輯寫進同名的成員方法中(如對應get請求方式,就將對應的處理邏輯寫在get()方法中),當沒有對應請求方式的成員方法時,會返回“405: Method Not Allowed”錯誤。
我們將代碼中定義的get()方法更改為post()后,再用瀏覽器重新訪問(瀏覽器地址欄中輸入網址訪問的方式為get請求方式),演示如下:
# coding:utf-8import tornado.webimport tornado.ioloopclass IndexHandler(tornado.web.RequestHandler):"""主路由處理類"""def post(self): # 我們修改了這里"""對應http的post請求方式"""self.write("Hello lewen!")if __name__ == "__main__":app = tornado.web.Application([(r"/", IndexHandler),])app.listen(8000)tornado.ioloop.IOLoop.current().start()?
?
-
Application
Tornado Web框架的核心應用類,是與服務器對接的接口,里面保存了路由信息表,其初始化接收的第一個參數就是一個路由信息映射元組的列表;其listen(端口)方法用來創建一個http服務器實例,并綁定到給定端口(注意:此時服務器并未開啟監聽)。
2. tornado.ioloop
tornado的核心io循環模塊,封裝了Linux的epoll和BSD的kqueue,tornado高性能的基石。 以Linux的epoll為例,其原理如下圖:
-
IOLoop.current()
返回當前線程的IOLoop實例。
-
IOLoop.start()
啟動IOLoop實例的I/O循環,同時服務器監聽被打開。
總結Tornado Web程序編寫思路
2.3 httpserver
上一節我們說在tornado.web.Application.listen()(示例代碼中的app.listen(8000))的方法中,創建了一個http服務器示例并綁定到給定端口,我們能不能自己動手來實現這一部分功能呢?
現在我們修改上一示例代碼如下:
# coding:utf-8import tornado.web import tornado.ioloop import tornado.httpserver # 新引入httpserver模塊class IndexHandler(tornado.web.RequestHandler):"""主路由處理類"""def get(self):"""對應http的get請求方式"""self.write("Hello lewen!")if __name__ == "__main__":app = tornado.web.Application([(r"/", IndexHandler),])# ------------------------------# 我們修改這個部分# app.listen(8000)http_server = tornado.httpserver.HTTPServer(app) http_server.listen(8000)# ------------------------------tornado.ioloop.IOLoop.current().start()?
在這一修改版本中,我們引入了tornado.httpserver模塊,顧名思義,它就是tornado的HTTP服務器實現。
我們創建了一個HTTP服務器實例http_server,因為服務器要服務于我們剛剛建立的web應用,將接收到的客戶端請求通過web應用中的路由映射表引導到對應的handler中,所以在構建http_server對象的時候需要傳出web應用對象app。http_server.listen(8000)將服務器綁定到8000端口。
實際上一版代碼中app.listen(8000)正是對這一過程的簡寫。
單進程與多進程
我們剛剛實現的都是單進程,可以通過命令來查看:
$ ps -ef | grep hello.py我們也可以一次啟動多個進程,修改上面的代碼如下:
# coding:utf-8import tornado.web import tornado.ioloop import tornado.httpserver class IndexHandler(tornado.web.RequestHandler):"""主路由處理類"""def get(self):"""對應http的get請求方式"""self.write("Hello lewen!")if __name__ == "__main__":app = tornado.web.Application([(r"/", IndexHandler),])http_server = tornado.httpserver.HTTPServer(app) # -----------修改----------------http_server.bind(8000)http_server.start(0)# ------------------------------tornado.ioloop.IOLoop.current().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.start(0),而我的虛擬機設定cpu核數為2,演示結果:
??
?
?
我們在前面寫的http_server.listen(8000)實際上就等同于:
http_server.bind(8000) http_server.start(8)說明
1.關于app.listen()
app.listen()這個方法只能在單進程模式中使用。
對于app.listen()與手動創建HTTPServer實例
http_server = tornado.httpserver.HTTPServer(app) http_server.listen(8000)這兩種方式,建議大家先使用后者即創建HTTPServer實例的方式,因為其對于理解tornado web應用工作流程的完整性有幫助,便于大家記憶tornado開發的模塊組成和程序結構;在熟練使用后,可以改為簡寫。
2.關于多進程
雖然tornado給我們提供了一次開啟多個進程的方法,但是由于:
- 每個子進程都會從父進程中復制一份IOLoop實例,如過在創建子進程前我們的代碼動了IOLoop實例,那么會影響到每一個子進程,勢必會干擾到子進程IOLoop的工作;
- 所有進程是由一個命令一次開啟的,也就無法做到在不停服務的情況下更新代碼;
- 所有進程共享同一個端口,想要分別單獨監控每一個進程就很困難。
不建議使用這種多進程的方式,而是手動開啟多個進程,并且綁定不同的端口。
2.4 options
在前面的示例中我們都是將服務端口的參數寫死在程序中,很不靈活。
tornado為我們提供了一個便捷的工具,tornado.options模塊——全局參數定義、存儲、轉換。
tornado.options.define()
用來定義options選項變量的方法,定義的變量可以在全局的tornado.options.options中獲取使用,傳入參數:
- name?選項變量名,須保證全局唯一性,否則會報“Option 'xxx' already defined in ...”的錯誤;
- default 選項變量的默認值,如不傳默認為None;
- type?選項變量的類型,從命令行或配置文件導入參數的時候tornado會根據這個類型轉換輸入的值,轉換不成功時會報錯,可以是str、float、int、datetime、timedelta中的某個,若未設置則根據default的值自動推斷,若default也未設置,那么不再進行轉換。可以通過利用設置type類型字段來過濾不正確的輸入。
- multiple?選項變量的值是否可以為多個,布爾類型,默認值為False,如果multiple為True,那么設置選項變量時值與值之間用英文逗號分隔,而選項變量則是一個list列表(若默認值和輸入均未設置,則為空列表 [ ])。
- help?選項變量的幫助提示信息,在命令行啟動tornado時,通過加入命令行參數 --help 可以查看所有選項變量的信息(注意,代碼中需要加入tornado.options.parse_command_line())。
tornado.options.options
全局的options對象,所有定義的選項變量都會作為該對象的屬性。
tornado.options.parse_command_line()
轉換命令行參數,并將轉換后的值對應的設置到全局options對象相關屬性上。追加命令行參數的方式是 --myoption=myvalue
新建opt.py,我們用代碼來看一下如何使用:
# -*- coding: utf-8 -*- # __auther__ = 'lewen'import tornado.web import tornado.ioloop import tornado.httpserver import tornado.options # 新導入的options模塊 tornado.options.define("port", default=8000, type=int, help="run server on the given port.") # 定義服務器監聽端口選項 tornado.options.define("lewen", default=[], type=str, multiple=True, help="lewen subjects.") # 無意義,演示多值情況class IndexHandler(tornado.web.RequestHandler):"""主路由處理類"""def get(self):"""對應http的get請求方式"""self.write("Hello lewen!")if __name__ == "__main__":tornado.options.parse_command_line()print(tornado.options.options.lewen) # 輸出多值選項app = tornado.web.Application([(r"/", IndexHandler),])http_server = tornado.httpserver.HTTPServer(app)http_server.listen(tornado.options.options.port)tornado.ioloop.IOLoop.current().start()執行如下命令開啟程序:
?$ python opt.py --port=9000 --lewen=python,c++,java,php,ios?效果如下:
tornado.options.parse_config_file(path)
從配置文件導入option,配置文件中的選項格式如下:
myoption = "myvalue" myotheroption = "myothervalue"我們用代碼來看一下如何使用,新建配置文件config,注意字符串和列表按照python的語法格式:
port = 8000 lewen = ["python","c++","java","php","ios"]修改opt.py文件:
# -*- coding: utf-8 -*- # __auther__ = 'lewen'# coding:utf-8import tornado.web import tornado.ioloop import tornado.httpserver import tornado.options # 新導入的options模塊# 要先定義 tornado.options.define("port", default=8000, type=int, help="run server on the given port.") # 定義服務器監聽端口選項 tornado.options.define("lewen", default=[], type=str, multiple=True, help="lewen subjects.") # 無意義,演示多值情況class IndexHandler(tornado.web.RequestHandler):"""主路由處理類"""def get(self):"""對應http的get請求方式"""self.write("Hello lewen!")if __name__ == "__main__":# tornado.options.parse_command_line() # 從命令行讀取tornado.options.parse_config_file("./config") # 從配置文件讀取參數print(tornado.options.options.lewen) # 輸出多值選項app = tornado.web.Application([(r"/", IndexHandler),])http_server = tornado.httpserver.HTTPServer(app)http_server.listen(tornado.options.options.port)tornado.ioloop.IOLoop.current().start()說明
1. 日志
當我們在代碼中調用parse_command_line()或者parse_config_file()的方法時,tornado會默認為我們配置標準logging模塊,即默認開啟了日志功能,并向標準輸出(屏幕)打印日志信息。
?
如果想關閉tornado默認的日志功能,可以在命令行中添加--logging=none 或者在代碼中執行如下操作:
from tornado.options import options, parse_command_line options.logging = None parse_command_line()?
2. 配置文件
我們看到在使用prase_config_file()的時候,配置文件的書寫格式仍需要按照python的語法要求,其優勢是可以直接將配置文件的參數轉換設置到全局對象tornado.options.options中;然而,其不方便的地方在于需要在代碼中調用tornado.options.define()來定義選項,而且不支持字典類型,故而在實際應用中大都不使用這種方法。
在使用配置文件的時候,通常會新建一個python文件(如config.py),然后在里面直接定義python類型的變量(可以是字典類型);在需要配置文件參數的地方,將config.py作為模塊導入,并使用其中的變量參數。
如config.py文件:
# conding:utf-8# Redis配置 redis_options = {'redis_host':'127.0.0.1','redis_port':6379,'redis_pass':'', }# Tornado app配置 settings = {'template_path': os.path.join(os.path.dirname(__file__), 'templates'),'static_path': os.path.join(os.path.dirname(__file__), 'statics'),'cookie_secret':'0Q1AKOKTQHqaa+N80XhYW7KCGskOUE2snCW06UIxXgI=','xsrf_cookies':False,'login_url':'/login','debug':True, }# 日志 log_path = os.path.join(os.path.dirname(__file__), 'logs/log')?
使用config.py的模塊中導入config,如下:
# conding:utf-8import tornado.web import configif __name__ = "__main__":app = tornado.web.Application([], **config.settings) ...?
轉載于:https://www.cnblogs.com/wenyule/articles/10353521.html
總結
以上是生活随笔為你收集整理的t2 初识Tornado的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 阿里云安全送您六道平安符,恭贺新春!
- 下一篇: 19.并发容器之BlockingQueu