摘要:對背后運(yùn)行機(jī)制感興趣,參考網(wǎng)上資料,結(jié)合源碼分析函數(shù)運(yùn)行時的機(jī)制,主要整理出函數(shù)調(diào)用棧。以分析首先官方文檔經(jīng)典示例現(xiàn)在來分析啟動時發(fā)生了什么代碼只列出用到的函數(shù),去掉注釋等函數(shù)導(dǎo)入運(yùn)行函數(shù)主要運(yùn)行調(diào)用返回類,然后調(diào)用返回類的。
對flask背后運(yùn)行機(jī)制感興趣,參考網(wǎng)上資料,結(jié)合源碼分析run函數(shù)運(yùn)行時的機(jī)制,主要整理出函數(shù)調(diào)用棧。以flask0.1分析
首先
Flask官方文檔經(jīng)典示例 hello.py
from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World!" if __name__ == "__main__": app.run()
現(xiàn)在來分析app.run()啟動時發(fā)生了什么? # 代碼只列出用到的函數(shù),去掉注釋等
flask.py
class Flask(object): def run(self, host="localhost", port=5000, **options): from werkzeug import run_simple if "debug" in options: self.debug = options.pop("debug") options.setdefault("use_reloader", self.debug) options.setdefault("use_debugger", self.debug) return run_simple(host, port, self, **options)
run函數(shù)導(dǎo)入from werkzeug import run_simple 運(yùn)行run_simple(host, port, self, **options)
werkzeug/serving.py
def run_simple(hostname, port, application, use_reloader=False, extra_files=None, threaded=False, processes=1): def inner(): srv = make_server(hostname, port, application, threaded, processes) try: srv.serve_forever() except KeyboardInterrupt: pass inner()
run_simple函數(shù)主要運(yùn)行inner(),inner調(diào)用make_server()返回類,然后調(diào)用返回類的serve_forever()。先來看看make_server()
werkzeug/serving.py
ddef make_server(host, port, app=None, threaded=False, processes=1): if threaded and processes > 1: raise ValueError("cannot have a multithreaded and " "multi process server.") elif threaded: class handler(BaseRequestHandler): multithreaded = True class server(ThreadingMixIn, WSGIServer): pass elif processes > 1: class handler(BaseRequestHandler): multiprocess = True max_children = processes - 1 class server(ForkingMixIn, WSGIServer): pass else: handler = BaseRequestHandler server = WSGIServer srv = server((host, port), handler) srv.set_app(app) return srv
make_server(hostname, port, application, threaded, processes) 傳入的都是默認(rèn)參數(shù),起作用的代碼是
else: handler = BaseRequestHandler server = WSGIServer srv = server((host, port), handler) srv.set_app(app) return srv
可以看出srv = server((host, port), handler) ,其實(shí)就是srv = WSGIServer((host, port), BaseRequestHandler),返回類就是WSGIServer ,綁定BaseRequestHandler。先看WSGIServer
wsgiref/simple_server.py
class WSGIServer(HTTPServer): def __init__= 標(biāo)準(zhǔn)庫 BaseHTTPServer.py class HTTPServer(SocketServer.TCPServer) : #WSGIServer繼承HTTPServer的__init__函數(shù),它自己沒有 ,這句是我加的方便理解 ,下同 def set_app(self,application): #這個就是make_server函數(shù)中調(diào)用的 set_app self.application = application def get_app(self): # return self.application 標(biāo)準(zhǔn)庫 BaseHTTPServer.py class HTTPServer(SocketServer.TCPServer) def __init__= 標(biāo)準(zhǔn)庫 SocketServer.py class TCPServer(BaseServer): 標(biāo)準(zhǔn)庫 SocketServer.py class TCPServer(BaseServer): def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): BaseServer.__init__(self, server_address, RequestHandlerClass) self.socket = socket.socket(self.address_family, self.socket_type) if bind_and_activate: # 這里調(diào)用socket.socket綁定端口 try: self.server_bind() self.server_activate() except: self.server_close() raise class BaseServer: def __init__(self, server_address, RequestHandlerClass): self.server_address = server_address self.RequestHandlerClass = RequestHandlerClass self.__is_shut_down = threading.Event() self.__shutdown_request = False def serve_forever(self, poll_interval=0.5): #這個就是run_simple中調(diào)用的serve_forever self.__is_shut_down.clear() try: while not self.__shutdown_request: r, w, e = _eintr_retry(select.select, [self], [], [], poll_interval) if self in r: self._handle_request_noblock() #調(diào)用serve_forever時調(diào)用_handle_request_noblock finally: self.__shutdown_request = False self.__is_shut_down.set() def _handle_request_noblock(self): try: request, client_address = self.get_request() except socket.error: return if self.verify_request(request, client_address): try: self.process_request(request, client_address) #繼續(xù) except: self.handle_error(request, client_address) self.shutdown_request(request) def process_request(self, request, client_address): self.finish_request(request, client_address) #繼續(xù) self.shutdown_request(request) def finish_request(self, request, client_address): self.RequestHandlerClass(request, client_address, self) # #繼續(xù) 并參見 werkzeug/serving.py make_server()
調(diào)用serve_forever后到了self.RequestHandlerClass(request, client_address, self) ,根據(jù)前面的代碼可知RequestHandlerClass 就是werkzeug/serving.py中的BaseRequestHandler,繼續(xù)
class BaseRequestHandler(WSGIRequestHandler): def __init__= 標(biāo)準(zhǔn)庫 wsgiref/simple_server.py class WSGIRequestHandler(BaseHTTPRequestHandler): #這句跟前面一樣繼承父類 wsgiref/simple_server.py class WSGIRequestHandler(BaseHTTPRequestHandler): def __init__= 標(biāo)準(zhǔn)庫 BaseHTTPServer.py class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler): #繼續(xù)父類 BaseHTTPServer.py class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler): def __init__= 標(biāo)準(zhǔn)庫 SocketServer.py class StreamRequestHandler(BaseRequestHandler): #繼續(xù)父類 SocketServer.py class StreamRequestHandler(BaseRequestHandler): #繼續(xù)父類 class BaseRequestHandler: def __init__(self, request, client_address, server): self.request = request self.client_address = client_address self.server = server self.setup() try: self.handle() # 運(yùn)行 參見 werkzeug/serving.py class BaseRequestHandler.handle finally: self.finish()
最后運(yùn)行了self.handle() 參見 werkzeug/serving.py class BaseRequestHandler.handle
前面有,再貼下看看
class BaseRequestHandler(WSGIRequestHandler): def handle(self): #1、調(diào)用的就是這個handle,覆蓋了父類的handle self.raw_requestline = self.rfile.readline() if self.parse_request(): self.get_handler().run(self.server.get_app()) #2、調(diào)用 get_handler()后,還繼續(xù)調(diào)用 run() ,get_app就是wsgiref/simple_server.py中WSGIServer類定義的函數(shù) def get_handler(self): # 3、看看它返回了什么 handler = self._handler_class if handler is None: class handler(ServerHandler): #4、新建一個類 返回的就是這個類 ,繼承ServerHandler """ 5、直接從其他文件copy出所需代碼,也就是handler的父類 wsgiref/simple_server.py class ServerHandler(SimpleHandler): 繼續(xù)父類 wsgiref/handlers.py class SimpleHandler(BaseHandler): def __init__(self,stdin,stdout,stderr,environ,multithread=True, multiprocess=False ): self.stdin = stdin self.stdout = stdout self.stderr = stderr self.base_env = environ self.wsgi_multithread = multithread self.wsgi_multiprocess = multiprocess class BaseHandler: #6、調(diào)用的就是這個類的run函數(shù) def run(self, application): try: self.setup_environ() self.result = application(self.environ, self.start_response) #7、調(diào)用app,也就是app=Flask() Flask類的 __call__ self.finish_response() except: try: self.handle_error() except: # If we get an error handling an error, just give up already! self.close() raise # ...and let the actual server figure it out. """ wsgi_multithread = self.multithreaded wsgi_multiprocess = self.multiprocess self._handler_class = handler rv = handler(self.rfile, self.wfile, self.get_stderr(), self.get_environ()) rv.request_handler = self return rv
可以看出最后調(diào)用的是application(self.environ, self.start_response) 這個application就是開始的app = Flask(__name__),調(diào)用類就是調(diào)用類的__call__ 函數(shù) ,繼續(xù)貼一下源碼
class Flask(object): def __call__(self, environ, start_response): return self.wsgi_app(environ, start_response) def wsgi_app(self, environ, start_response): with self.request_context(environ): rv = self.preprocess_request() if rv is None: rv = self.dispatch_request() response = self.make_response(rv) response = self.process_response(response) return response(environ, start_response)
OK,大功告成,最后調(diào)用wsgi_app(self, environ, start_response)函數(shù),這個就是返回響應(yīng)的主函數(shù)了!!
從整個流程中,flask利用WSGIServer類啟動監(jiān)聽端口并綁定,BaseRequestHandler類接收、返回相應(yīng)的信息!完全符合WSGI要求。
剩余的工作就太過于底層,不好深入分析了。也畫了調(diào)用流程圖,不過太大不好傳,如果有需要可以繼續(xù)交流!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/40755.html
摘要:是應(yīng)用性能管理監(jiān)控解決方案提供商。目錄是列出的命令腳本所在目錄。包含文件如下的函數(shù)是命令執(zhí)行的入口。而對于硬件信息的檢測則由進(jìn)行。文檔地址源碼仔細(xì)看下去,太復(fù)雜了。下一篇再分析一個請求到結(jié)束探針工作的完整過程吧。 Newrelic 是APM(Application Performance Management)(應(yīng)用性能管理/監(jiān)控)解決方案提供商。項目中,通常用它來追蹤應(yīng)用的性能。最近...
摘要:上次遺留了兩個問題先說一下自己的看法問題明明一個線程只能處理一個請求那么棧里的元素永遠(yuǎn)是在棧頂那為什么需要用棧這個結(jié)構(gòu)用普通變量不行嗎和都是線程隔離的那么為什么要分開我認(rèn)為在的情況下是可以不需要棧這個結(jié)構(gòu)的即使是單線程下也不需要原本我以為在 上次遺留了兩個問題,先說一下自己的看法問題:1.明明一個線程只能處理一個請求,那么棧里的元素永遠(yuǎn)是在棧頂,那為什么需要用棧這個結(jié)構(gòu)?用普通變量不行...
摘要:本文就主要針對一個應(yīng)用的運(yùn)行過程進(jìn)行簡要分析,后續(xù)文章還會對框架的一些具體問題進(jìn)行分析。所有的請求處理過程,都會在這個上下文對象中進(jìn)行。和一些全局變量注意當(dāng)進(jìn)入這個上下文對象時,會觸發(fā)。 相信很多初學(xué)Flask的同學(xué)(包括我自己),在閱讀官方文檔或者Flask的學(xué)習(xí)資料時,對于它的認(rèn)識是從以下的一段代碼開始的: from flask import Flask app = Flask(...
摘要:官方示例第一行類對象,這個無需解釋。請求對象的端點(diǎn)請求視圖函數(shù)的參數(shù)通過源碼的注釋我們可以知道,都只是對庫的進(jìn)行了一層包裝并加入一些屬性。接下來會有更多關(guān)于和相關(guān)文章放出來,敬請期待參考文檔項目源碼版本注釋版 Flask 是一個 Python 實(shí)現(xiàn)的 Web 開發(fā)微框架, 有豐富的生態(tài)資源。本文從一段官方的示例代碼通過一步步打斷點(diǎn)方式解釋 Flask 內(nèi)部的運(yùn)行機(jī)制,在一些關(guān)鍵概念會...
摘要:簡介官網(wǎng)上對它的定位是一個微開發(fā)框架。另外一個必須理解的概念是,簡單來說就是一套和框架應(yīng)用之間的協(xié)議。功能比較豐富,支持解析自動防止攻擊繼承變量過濾器流程邏輯支持代碼邏輯集成等等。那么,從下一篇文章,我們就正式開始源碼之旅了 文章屬于作者原創(chuàng),原文發(fā)布在個人博客。 flask 簡介 Flask 官網(wǎng)上對它的定位是一個微 python web 開發(fā)框架。 Flask is a micro...
閱讀 3060·2021-11-18 10:02
閱讀 3327·2021-11-02 14:48
閱讀 3391·2019-08-30 13:52
閱讀 555·2019-08-29 17:10
閱讀 2083·2019-08-29 12:53
閱讀 1403·2019-08-29 12:53
閱讀 1027·2019-08-29 12:25
閱讀 2164·2019-08-29 12:17