Flask的请求上下文机制

Posted yaraning

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flask的请求上下文机制相关的知识,希望对你有一定的参考价值。

准备知识

面向对象双下方法

__call__ 对象后面加括号,触发执行

 

为什么设计上下文这样的机制?

就是保证多线程环境下,实现线程之间的隔离.

 

在了解flask上下文机制之前,我们先了解下线程的数据安全.

线程安全

 技术图片

如上代码段,在1s内开启20个线程,执行add_num(),结果foo.num都为 19,说明线程间数据是不隔离的.

技术图片

那么,如何保证线程间数据隔离呢? 有一种 threading.local 方法

Thread Local

threading.local 在多线程操作时,为每一个线程开辟一个空间来保存它的值,使得线程之间的值互不影响.

import time
from threading import Thread,local

class Foo(local):
    num = 0

foo = Foo()

def add_num(i):
    foo.num = i
    time.sleep(1)
    print(i,foo.num)

for i in range(20):
    task = Thread(target=add_num,args=(i,))
    task.start()

也可以自定义一个线程安全: 定义一个全局字典,key为当前线程的线程ID,value为具体的值

技术图片
import copy
import time
from threading import Thread,get_ident

class Foo():
    num = 0

foo = Foo()

dic = {}
def add_num(i):
    dic[get_ident()] = copy.copy(foo)
    dic[get_ident()].num = i
    time.sleep(1)
    print(get_ident(),dic[get_ident()].num)

for i in range(5):
    task = Thread(target=add_num,args=(i,))
    task.start()
自定义线程安全示例

Flask的上下文机制就是基于Werkzeug 的 Local Stack 实现的. 而Local Stack又依赖于local类.

 Flask的请求上下文机制

先启动一个flask项目,会执行app.run()方法,这是整个项目的入口,执行run方法,里面封装了werkzeug模块中的run_simple.

from flask import Flask

app = Flask(__name__)

app.run()

 

技术图片

 

我们用 werkzeug 来实现一个请求和响应:

from werkzeug.serving import run_simple
from werkzeug.wrappers import Request,Response

@Request.application
def app(req):
    print(req)
    return Response("200 OK!")

run_simple("127.0.0.1", 5000, app)

run_simple最终就是执行 app函数,即 app(), 那么在flask中,

run_simple中的 self 就是Flask对象,所以执行 run_simple 就触发了Flask的__call__方法.

请求上文

触发执行__call__方法,__call__方法的逻辑很简单,直接执行wsgi_app方法,将原始请求数据和一个响应函数传进去。

技术图片

 

以上是关于Flask的请求上下文机制的主要内容,如果未能解决你的问题,请参考以下文章

[Python]Flask内存马学习

[Python]Flask内存马学习

源码解读:Flask 上下文核心机制

flask基础之请求钩子

14Flask请求上下文

Flask中的请求上下文和应用上下文