摘要:对背后运行机制感兴趣,参考网上资料,结合源码分析函数运行时的机制,主要整理出函数调用栈。以分析首先官方文档经典示例现在来分析启动时发生了什么代码只列出用到的函数,去掉注释等函数导入运行函数主要运行调用返回类,然后调用返回类的。
对flask背后运行机制感兴趣,参考网上资料,结合源码分析run函数运行时的机制,主要整理出函数调用栈。以flask0.1分析
首先
Flask官方文档经典示例 hello.py
from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello World!" if __name__ == "__main__": app.run()
现在来分析app.run()启动时发生了什么? # 代码只列出用到的函数,去掉注释等
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函数导入from werkzeug import run_simple 运行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函数主要运行inner(),inner调用make_server()返回类,然后调用返回类的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) 传入的都是默认参数,起作用的代码是
else: handler = BaseRequestHandler server = WSGIServer srv = server((host, port), handler) srv.set_app(app) return srv
可以看出srv = server((host, port), handler) ,其实就是srv = WSGIServer((host, port), BaseRequestHandler),返回类就是WSGIServer ,绑定BaseRequestHandler。先看WSGIServer
wsgiref/simple_server.py
class WSGIServer(HTTPServer): def __init__= 标准库 BaseHTTPServer.py class HTTPServer(SocketServer.TCPServer) : #WSGIServer继承HTTPServer的__init__函数,它自己没有 ,这句是我加的方便理解 ,下同 def set_app(self,application): #这个就是make_server函数中调用的 set_app self.application = application def get_app(self): # return self.application 标准库 BaseHTTPServer.py class HTTPServer(SocketServer.TCPServer) def __init__= 标准库 SocketServer.py class TCPServer(BaseServer): 标准库 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: # 这里调用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中调用的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() #调用serve_forever时调用_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) #继续 except: self.handle_error(request, client_address) self.shutdown_request(request) def process_request(self, request, client_address): self.finish_request(request, client_address) #继续 self.shutdown_request(request) def finish_request(self, request, client_address): self.RequestHandlerClass(request, client_address, self) # #继续 并参见 werkzeug/serving.py make_server()
调用serve_forever后到了self.RequestHandlerClass(request, client_address, self) ,根据前面的代码可知RequestHandlerClass 就是werkzeug/serving.py中的BaseRequestHandler,继续
class BaseRequestHandler(WSGIRequestHandler): def __init__= 标准库 wsgiref/simple_server.py class WSGIRequestHandler(BaseHTTPRequestHandler): #这句跟前面一样继承父类 wsgiref/simple_server.py class WSGIRequestHandler(BaseHTTPRequestHandler): def __init__= 标准库 BaseHTTPServer.py class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler): #继续父类 BaseHTTPServer.py class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler): def __init__= 标准库 SocketServer.py class StreamRequestHandler(BaseRequestHandler): #继续父类 SocketServer.py class StreamRequestHandler(BaseRequestHandler): #继续父类 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() # 运行 参见 werkzeug/serving.py class BaseRequestHandler.handle finally: self.finish()
最后运行了self.handle() 参见 werkzeug/serving.py class BaseRequestHandler.handle
前面有,再贴下看看
class BaseRequestHandler(WSGIRequestHandler): def handle(self): #1、调用的就是这个handle,覆盖了父类的handle self.raw_requestline = self.rfile.readline() if self.parse_request(): self.get_handler().run(self.server.get_app()) #2、调用 get_handler()后,还继续调用 run() ,get_app就是wsgiref/simple_server.py中WSGIServer类定义的函数 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): 继续父类 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、调用的就是这个类的run函数 def run(self, application): try: self.setup_environ() self.result = application(self.environ, self.start_response) #7、调用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
可以看出最后调用的是application(self.environ, self.start_response) 这个application就是开始的app = Flask(__name__),调用类就是调用类的__call__ 函数 ,继续贴一下源码
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,大功告成,最后调用wsgi_app(self, environ, start_response)函数,这个就是返回响应的主函数了!!
从整个流程中,flask利用WSGIServer类启动监听端口并绑定,BaseRequestHandler类接收、返回相应的信息!完全符合WSGI要求。
剩余的工作就太过于底层,不好深入分析了。也画了调用流程图,不过太大不好传,如果有需要可以继续交流!
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/40755.html
摘要:是应用性能管理监控解决方案提供商。目录是列出的命令脚本所在目录。包含文件如下的函数是命令执行的入口。而对于硬件信息的检测则由进行。文档地址源码仔细看下去,太复杂了。下一篇再分析一个请求到结束探针工作的完整过程吧。 Newrelic 是APM(Application Performance Management)(应用性能管理/监控)解决方案提供商。项目中,通常用它来追踪应用的性能。最近...
摘要:上次遗留了两个问题先说一下自己的看法问题明明一个线程只能处理一个请求那么栈里的元素永远是在栈顶那为什么需要用栈这个结构用普通变量不行吗和都是线程隔离的那么为什么要分开我认为在的情况下是可以不需要栈这个结构的即使是单线程下也不需要原本我以为在 上次遗留了两个问题,先说一下自己的看法问题:1.明明一个线程只能处理一个请求,那么栈里的元素永远是在栈顶,那为什么需要用栈这个结构?用普通变量不行...
摘要:本文就主要针对一个应用的运行过程进行简要分析,后续文章还会对框架的一些具体问题进行分析。所有的请求处理过程,都会在这个上下文对象中进行。和一些全局变量注意当进入这个上下文对象时,会触发。 相信很多初学Flask的同学(包括我自己),在阅读官方文档或者Flask的学习资料时,对于它的认识是从以下的一段代码开始的: from flask import Flask app = Flask(...
摘要:官方示例第一行类对象,这个无需解释。请求对象的端点请求视图函数的参数通过源码的注释我们可以知道,都只是对库的进行了一层包装并加入一些属性。接下来会有更多关于和相关文章放出来,敬请期待参考文档项目源码版本注释版 Flask 是一个 Python 实现的 Web 开发微框架, 有丰富的生态资源。本文从一段官方的示例代码通过一步步打断点方式解释 Flask 内部的运行机制,在一些关键概念会...
摘要:简介官网上对它的定位是一个微开发框架。另外一个必须理解的概念是,简单来说就是一套和框架应用之间的协议。功能比较丰富,支持解析自动防止攻击继承变量过滤器流程逻辑支持代码逻辑集成等等。那么,从下一篇文章,我们就正式开始源码之旅了 文章属于作者原创,原文发布在个人博客。 flask 简介 Flask 官网上对它的定位是一个微 python web 开发框架。 Flask is a micro...
阅读 3049·2021-11-18 10:02
阅读 3315·2021-11-02 14:48
阅读 3384·2019-08-30 13:52
阅读 527·2019-08-29 17:10
阅读 2070·2019-08-29 12:53
阅读 1392·2019-08-29 12:53
阅读 1018·2019-08-29 12:25
阅读 2155·2019-08-29 12:17