Flask 原始碼剖析——服務啟動篇

發表於2016-06-24

【Flask官方文件經典示例】 hello.py

輸入以下命令啟動應用程式:

開啟你的瀏覽器並在位址列輸入http://127.0.0.1:5000/ 。【圖1-1】顯示連線到應用程式後的瀏覽器。

Flask 原始碼剖析——服務啟動篇
圖1-1 hello.py Flask應用程式

服務是怎麼啟動的

app.run()開始,這行程式碼表示啟動一個服務。我們看到appFlask一個物件,而run()是該物件的一個方法。我們先簡單的認為定義了一個類,然後例項化這個類並呼叫該類的一個方法,如下:

【示例1-1】example-1-1.py

如果我們執行【示例1-1】這段程式碼,會發現什麼都沒有發生。然而,【Flask官方文件經典示例】不是這樣的,當你執行後它是下面這樣的:

很自然的可以想到,【Flask官方文件經典示例】中的app.run()不簡單,我們可以看看run()方法定義,如下:

在這個方法中,我們先忽略一些配置操作,重點關注run_simple()函式,發現該函式是從werkzeug.serving模組中匯入的。

到了這裡我們就不得不提一下Werkzeug了,官方文件定義:Werkzeug是為Python設計的HTTP和WSGI實用程式庫。至於它有什麼作用,我們在這裡暫且不討論,先跟到程式碼裡面看看它都做了什麼。

我們看到這個run_simple()函式裡面還巢狀了一個inner()函式,裡面有幾行關鍵程式碼,如下:

從上面的程式碼,我們看到在inner()函式裡面呼叫了make_server()函式來建立一個類例項,該例項會呼叫serve_forever()方法讓服務一直執行,等待客戶端的請求。到這裡我們大概找到了服務啟動的入口了,想知道具體是怎麼啟動,我們還需要深入挖掘一下。

因為呼叫run_simple()函式時引數threadedprocesses給的都是預設值,分別為False1,所以在這裡make_server()函式其實是建立了一個BaseWSGIServer類例項,並呼叫該例項的serve_forever()方法,具體make_server()函式如下:

找到BaseWSGIServer類,如下程式碼:

【注意】接下來的程式碼巢狀呼叫比較多,所以最好是能對照著原始碼來看。

srv.serve_forever()其實是BaseWSGIServer類中的serve_forever()方法,然後我們發現BaseWSGIServer類繼承了HTTPServer類,且BaseWSGIServerserve_forever()方法中呼叫了HTTPServerserve_forever()方法。找到HTTPServer類,如下程式碼:

HTTPServer類中並沒有serve_forever()方法,且這個類繼承了 SocketServer.TCPServer,我們再找到TCPServer類,然而它也沒有serve_forever()方法,且這個類繼承了BaseServer類,所以再去BaseServer裡面看看,如下程式碼:

所以前面看到的srv.serve_forever()其實是呼叫了BaseServer裡面的serve_forever()方法,它接受一個引數poll_interval,用於表示select輪詢的時間。然後進入一個無限迴圈,呼叫select方式進行網路IO監聽。也就是說app.run()啟動的是一個BaseWSGIServer,該服務通過一層一層的繼承建立socket來進行網路監聽,等待客戶端連線。

至此,Flask服務是怎麼啟動的應該有個基本的瞭解了。

整理一下相關server類的繼承關係,如下:

BaseWSGIServer–>HTTPServer–>SocketServer.TCPServer–>BaseServer

從上面的類繼承關係,我們可以很容易的理解,因為Flask是一個Web框架,所以需要一個HTTP服務,而HTTP服務是基於TCP服務的,而TCP服務最終會有一個基礎服務來處理socket。這一條線都能夠解釋的通。但是,那個BaseWSGIServer是個什麼鬼?為什麼會需要一層這個服務?這也是我想要去研究的,所以我會在下一篇裡面進行講解。

相關文章