Python Web服務高並發框架【1】(Tornado)


本節學習目標:

 (1)了解Tornado的特點
 (2)了解Tornado工作流程
 (3)掌握Tornado在Window及Linux中的安裝
 (4)理解同步、異步
 (5)協程基礎編程

本節課程內容:

一、Tornado介紹

Tornado是使用Python編寫的一個強大的可擴展的Web服務器。除了FriendFeed和Facebook外,還有很多公司在生產上轉向Tornado,包括Quora、Turntable.fm、Bit.ly及MyYearbook等。

相對於其它Python的網絡框架,Tornado有如下特點:

  • 完備的Web框架:與Django、Flask框架等一樣,Tornado也提供了URL路由映射、Request上下文、基於模板引擎的頁面渲染技術等開發Web應用的必備工具。
  • 非阻塞式服務器且速度相當快:tornado每秒可以處理數以千計的連接,其得利於非阻塞的方式和對epoll的運用。
  • 高效的網絡庫:其性能可以與Twisted、Gevent等底層Python框架相媲美,提供了異步I/O支持、超時時間處理。這使得Tornado除了可以作為web服務器框架,還可以用來做爬蟲應用、物聯網網關、游戲服務器等后台應用。
  • 提供高效HTTPClient:除了服務器端框架,tornado還提供了基於異步框架的HTTP客戶端。
  • 提供高效的內部HTTPServer:雖然其他Python網絡框架(Django、Flask)也提供了內部HTTP服務器,但他們由於性能原因只能用於測試環境。而tornado的HTTPServer與tornado異步調用緊密結合,可以直接用於生成環境。
  • 完備的WebSocket支持WebSocket是HTML5的一種新標准,實現了瀏覽器和服務器之間的雙向實時通信。
    根據以上特點

Tornado常被用作大型站點的接口服務框架,而不像Django那樣着眼於建立完整的大型網站。除此之外,Tornado還常用於異步及協程編程、身份認證框架、獨特的非WSGI部署方式等等。

二、Tornado工作流程圖

三、安裝Tornado

Tornado已經被配置到PyPI中,在Windows和Linux中都可以通過一條pip命令完成安裝
#pip install tornado
該條命令運行在Linux操作系統中。安裝結果如下圖所示:
安裝(tornado).png

四、同步/異步及yield

協程是Tornado中推薦的變成方式,使用協程可以開發出簡捷、高效的異步處理代碼。首先要掌握的內容是:
(1) 同步I/O和異步I/O

  • 同步I/O(synchronous Input/Output operation):
      導致請求進程阻塞,直到I/O操作完成。在Python中,同步I/O可以被理解為一個被調用的I/O函數會阻塞調用函數的執行。
  • 異步I/O(asynchronous Input/Output operation):
      不會導致請求進程阻塞。可以理解為一個被調用的I/O函數不會阻塞調用函數的執行。
    代碼舉例如下
#同步I/O --- 使用HTTPClinet客戶端
from tornado.httpclient import HTTPClient #tornado的同步HTTP客戶端類
print '訪問前'
def syn_visit():
    http_client = HTTPClient()
    print '訪問中...'  
    response = http_client.fetch("http://www.lanou3g.com") #阻塞,直到訪問完成
    print response.body
syn_visit()
print '訪問后'

其中,HTTPClinet是tornado的同步訪問HTTP客戶端。上述代碼中的synchronous_visit()函數使用了典型的同步I/O操作訪問www.baidu.com網站,該函數的執行時間取決於網絡速度、服務器響應速度等,只有對網站訪問完成並獲取響應結果后,才能完成synchronous_visit()整個函數的執行。

#異步I/O --- 使用AsyncHTTPClient客戶端
from tornado.httpclient import AsyncHTTPClient #tornado的異步HTTP客戶端類
def handle_response(response):
    print response.body  
print '訪問前'
def asyn_visit():
    http_client = AsyncHTTPClient()
    print '訪問中'
    response = http_client.fetch("http://www.lanou3g.com",callback=handle_response) #不會阻塞進程
asyn_visit()
print '訪問后'  

其中,AsyncHTTPClient是Tornado的異步訪問HTTP客戶端。在上述代碼中的asyn_visit()函數中使用AsyncHTTPClient對第三方網站進行異步訪問,http_client.fetch()函數會在調用后立刻返回而無須等待實際訪問的完成,從而導致asyn_visit()也會立刻執行完成。當訪問實際完成后,AsyncHTTPClient會調用callback參數指定的函數。
(2) Python關鍵字yield
協程是Tornado中進行異步I/O代碼開發的方法。協程使用了Python關鍵字yield將調用者掛起和恢復執行。所以在學習協程編程之前,首先掌握Python中yield關鍵字的使用。
  迭代器在Python編程中適用范圍很廣,那么開發者如何定制自己的迭代器呢?答案就是使用yield關鍵字。

當調用任何定義中包含yield關鍵字的函數都不會執行該函數,而會或得一個對應函數的迭代器。

示例代碼如下圖:

#自定義迭代器函數
def demoIterator():
    print "The first call of next()"
    yield 'number 1'
    print "The second call of next()"
    yield 'number 2'
    print "The third call of next()"
    yield 'number3'
print type(demoIterator())  #<type 'generator'>
for i in demoIterator():
    print i

使用for循環會每次調用迭代器的next()函數,將執行迭代器函數,並返回yield的結果作為迭代返回元素。

五、協程編程基礎

使用Tornado協程可以開發出類似同步代碼的異步行為。同時,因為協程本身不使用線程,所以減少了線程上下文切換的開銷。

1、協程函數的編寫
用協程技術開發網頁訪問功能,示例代碼如下:

# -*- coding: utf-8 -*-
from tornado import gen  #引入協程庫gen
from tornado.httpclient import AsyncHTTPClient #引入框架中的異步客戶端
@gen.coroutine
def cor_visit():
    http_client = AsyncHTTPClient()
    response = yield http_client.fetch('http://www.lanou3g.com')
    print response.body

上述代碼中,仍然使用了異步客戶端AsyncHTTPClient進行頁面訪問,修飾器@gen.coroutine聲明其是一個協程函數。由於使用了yield關鍵字,所以代碼中不用再編寫回調函數用於處理訪問結果,而可以直接在yield語句的后面編寫結果處理語句。
2、協程函數的使用
由於tornado協程基於Python的yield關鍵字實現,所以不能像調用一般函數去調用。調用協程函數的方式有三種:
(1) 第一種方式:
在本身是協程的函數內調用另一個協程函數,可以通過yield關鍵字調用。

@gen.coroutine
def use_cor():
    print "開始調用其它協程函數"
    yield cor_visit()
    print "結束調用其它協程函數"

(2) 第二種方式:
在IOLoop尚未啟動時,通過IOLoop的run_sync()函數。

from tornado import gen # 引入協程庫
from tornado.ioloop import IOLoop
from tornado.httpclient import AsyncHTTPClient
def loop_stop_visit():
    print('開始調用協程')
    IOLoop.current().run_sync(lambda: cor_visit())
    print('結束協程調用')
loop_stop_visit()

其中,IOLoop 是Tornado的主事件循環對象【IOLoop會在后面有專門的章節去講解】,Tornado程序通過它監聽外部客戶端的訪問請求,並執行相應的操作,當程序尚未進入IOLoop的runing狀態時,可以通過run_sync()函數調用協程函數。run_sync()函數會將阻塞當前函數的執行,直到被調用的協程函數執行完成。
(2) 第三種方式:
在IOLoop已經啟動時,通過IOLoop的spawn_callback()函數調用。

def loop_start_visit():
    IOLoop.current().spawn_callback(coroutine_visit)
loop_start_visit()    #調用

上述代碼中,spawn_callback()函數不會等待被調用的協程函數執行完成,所以spawn_callback()之前和之后的語句會被連續執行,而cor_visit本身將會有IOLoop在合適的時機進行調用,並且spawn_callback函數沒有為開發者提供獲取協程函數調用函數返回值的方法,所以只能用spawn_callback()調用沒有返回值的協程函數


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM