Flask 是一個微框架(Micro framework),所謂微框架,它就是很輕量級的,做者劃分出了Flask應該負責什麼(請求路由、處理請求、返回響應)、不該該負責什麼(數據庫抽象、表單驗證)。它倡導地是不要重複造輪子,結合社區優秀的庫,使得Flask更加靈活、定製性更強。python
先寫一個簡單的Flask應用(main.py)shell
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello World'
app.run("127.0.0.1", 80, debug=True)
複製代碼
執行測試數據庫
> python main.py
> curl http://127.0.0.1:80
Hello World
複製代碼
查看一下app.run()
函數源碼flask
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
...
from werkzeug.serving import run_simple
try:
run_simple(host, port, self, **options)
finally:
self._got_first_request = False
複製代碼
核心邏輯是執行run_simple
函數,而且第三個參數self
是Flask對象安全
看一下Flask
類的實現bash
class Flask:
def wsgi_app(self, environ, start_response):
# 將請求信息包裝爲一個ctx對象
ctx = self.request_context(environ)
error = None
try:
try:
# ctx壓棧
ctx.push()
# 分發 處理
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except: # noqa: B001
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
# ctx 出棧
ctx.auto_pop(error)
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
複製代碼
當請求到來時,程序在調用app時,因爲實現了__call__
函數,則經過該函數調用了wsgi_app()
函數markdown
具體分析wsgi_app函數:多線程
Local
類是用werkzeug
庫實現的一個用於類存儲數據的類,它支持多線程安全存儲。app
使用__storage__
(dict類型)存儲數據,可是經過獲取到的線程id做爲標識來進行隔離,讓每一個線程讀寫本身線程的數據 __storage__
的結構是這樣的框架
{
"線程id1": {"stack": [ctx,]},
"線程id2": {"stack": []},
}
複製代碼
實際源碼
from thread import get_ident
class Local(object):
__slots__ = ("__storage__", "__ident_func__")
def __init__(self):
object.__setattr__(self, "__storage__", {})
object.__setattr__(self, "__ident_func__", get_ident)
def __getattr__(self, name):
# 重寫了該方法,首先獲取當前線程id,而後去讀取該線程id下的數據
try:
return self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)
def __setattr__(self, name, value):
# 重寫了該方法,首先獲取當前線程id,而後去寫入該線程id下的數據
ident = self.__ident_func__()
storage = self.__storage__
try:
storage[ident][name] = value
except KeyError:
storage[ident] = {name: value}
def __delattr__(self, name):
# 重寫了該方法,首先獲取當前線程id,而後去刪除該線程id下的數據
try:
del self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)
複製代碼
LocalStack
是基於Local
類實現的棧類,因此它支持線程安全。 實際源碼
class LocalStack(object):
def __init__(self):
self._local = Local()
def push(self, obj):
"""Pushes a new item to the stack"""
rv = getattr(self._local, "stack", None)
if rv is None:
self._local.stack = rv = []
rv.append(obj)
return rv
def pop(self):
"""Removes the topmost item from the stack, will return the old value or `None` if the stack was already empty. """
stack = getattr(self._local, "stack", None)
if stack is None:
return None
elif len(stack) == 1:
release_local(self._local)
return stack[-1]
else:
return stack.pop()
@property
def top(self):
try:
return self._local.stack[-1]
except (AttributeError, IndexError):
return None
複製代碼