Flask-上下文管理

一、threading-local

1、threding-local

作用:为每一个线程开辟一块空间进行数据存储
from
threading import local from threading import Thread import time # 示例化local对象 ret=local() def task(s): global ret ret.value=s time.sleep(2) print(ret.value) # 开启10个线程 for i in range(10): t=Thread(target=task,args=(i,)) t.start()

2、自定义local

# 如果有协程则使用协程唯一标识getcurrent
try:
from greenlet import getcurrent as get_ident
except Exception as e:
from threading import Thread,get_ident

class Local(object):
# 线程的唯一标识
ident = get_ident()
def __init__(self):
# 执行父类__setattr__
object.__setattr__(self,"storage",{})

def __setattr__(self,k, v):
"""
构造dict
storage={
ident:{val:0},
ident:{val:1},
ident:{val:3},
ident:{val:4},
}
"""
if self.ident in self.storage:
self.storage[self.ident][k] = v
else:
self.storage[self.ident] = {k: v}

def __getattr__(self,k):

return self.storage[self.ident][k]


obj=Local()

def task(arg):
# 执行__setattr__
obj.var=arg
# 执行__getattr__
v=obj.var
print(v)

for i in range(10):
t = Thread(target=task,args=(i,))
t.start()

二、上下文管理源码分析

1、上下文管理本质(类似于threading.local)
            1、每一个线程都会在Local类中创建一条数据

                  {
                    “唯一标识”:{stark:[ctx,]}
                    “唯一标识”:{stark:[ctx,]}

                   }

            2、当请求进来之后,将请求相关数据添加到列表里面[request,],以后如果使用时,就去读取
            3、列表中的数据,请求完成之后,将request从列表中移除
2、在源码中分析上下文管理
        
        第一阶段:执行__call__--->app.wsgi-->将ctx(request,session)封装为RequestContent()在(open_session), app_ctx(g,app)封装为APPContent()通过LocalStack将这两个类放入Local对象中
                   
        第二阶段:视图函数导入:request/session/g/app ,通过偏函数(_lookup_req_object)在通过(LocalProxy())去LocalStack中的Local类中对其进行增删改查操作 

     第三阶段:请求处理完毕
       
      - 通过save_session将签名session保存到cookie 
      -通过ctx.pop()去LocalStack中的Local类- 将ctx删除           

有关面试问题

问题一:flask和django的区别:
  对于django来说,内部组件特别多,自身功能强大,有点大而全,而flask,内置组件很少,但是它的第三方组件很多,扩展性强,有点短小精悍,而它们之间也有相似之处,
  因为它们两个框架都没有写sockte,都是基于wsgi协议做的,在此之外,flask框架中的上下文管理较为耀眼。

  

  相同点:它们两个框架都没有写sockte,都是基于wsgi协议做的
  请求相关数据传递的方式不同:django:通过传递request参数取值
                flask:见问题二
           组件不同:django组件多
                flask组件少,第三方组件丰富

问题1.1: flask上下文管理:
  简单来说,falsk上下文管理可以分为三个阶段:
        1、请求进来时,将请求相关的数据放入上下问管理中
        2、在视图函数中,要去上下文管理中取值
        3、请求响应,要将上下文管理中的数据清除
  
  详细点来说:
        1、请求刚进来,将request,session封装在RequestContext类中,app,g封装在AppContext类中,并通过LocalStack将requestcontext和appcontext放入Local类中
        2、视图函数中,通过localproxy--->偏函数--->localstack--->local取值
        3、请求相应时,先执行save.session()再各自执行pop(),将local中的数据清除
        

问题1.2 flask第三方组件
  flask:
      -flask-session 默认放入cookie,可以放入redis
      -flask-redis
      -flask-migrate
      -flask-script
      -blinker 信号
 公共: DBUtils 数据库连接池
      wtforms 表单验证+生成HTML标签
      sqlalchemy
  自定义:Auth 参考falsk-login

问题二:Flask中的session是什么时候创建,什么时候销毁的?
  当请求进来时,会将requset和session封装为一个RequestContext对象,通过LocalStack将RequestContext放入到Local对象中,因为
请求第一次来session是空值,所以执行open_session,给session(uuid4())赋值,再通过视图函数处理,请求响应时执行save.session,将签名session写入cookie中,再讲Local中的数值pop掉。

问题三:flask中一共有几个LocalStack和Local对象
  两个LocalStack,两个Local
  request、session共同用一个LocalStack和Local
  g、app共同用一个Localstack和Local

问题四: 为什么把请求放到RequestContext中:
   因为request和session都是在视图中操作频繁的数据,也是用户请求需要用的数据,将request和session封装在RequestContext中top,pop一次就可以完成,而单独不封装在一起就会多次操作,

    ctx = RequestContext(request,session)

问题五:local作用
    -保存 请求上下文对象和app上下文对象

     -localstack的源码与threading.local(线程处理)作用相似,不同之处是Local是通过greenlet(协程)获取唯一标识,粒度更细

      

 问题六:Localstack作用

    2、将local对象中的数据维护成一个栈【ctx,ctx】(先进后出)

         {
            “协程或线程的唯一标识”: { stack:[ctx,ctx,ctx,] }
         }

    

为什么维护成一个栈?
   当是web应用时:不管是单线程还是多线程,栈中只有一个数据

   - 服务端单线程:
    {
    111:{stack: [ctx, ]}
    }
   - 服务端多线程:
    {
    111:{stack: [ctx, ]}
    112:{stack: [ctx, ]}
    }

离线脚本:可以在栈中放入多个数据

with app01.app_context():
  print(current_app)
  with app02.app_context():
    print(current_app)
  print(current_app)

 

 问题七:什么是g?

    g 相当于一次请求的全局变量,当请求进来时将g和current_app封装为一个APPContext类,在通过LocalStack将Appcontext放入Local中,取值时通过偏函数,LocalStack、loca l中取值,响应时将local中的g数据删除:

 问题八:怎么获取Session/g/current_app/request

    通过 、偏函数(lookup_req_object)、Localstack、Local取值

 问题九: 技术点:
  - 反射 (LocalProxy())
  - 面向对象,封装:RequestContext
  - 线程(threading.local)
  - 笔试:自己写一个类+列表 实现栈。(LocalStack)

问题十:python基本哪些内容比较重要:

1、反射

  -CBV

  -django配置文件

  -wtforms中的Form()示例化中 将"_fields中的数据封装到From类中"

2、装饰器 (迭代器,生成器)
  -flask:路由、装饰器

  -认证

  -csrf

3、面向对象

  -继承、封装、多态(简单描述)

 -双下划线:

    __mro__ wtform中 FormMeta中继承类的优先级

     __dict__    

    __new__ ,实例化但是没有给当前对象
        wtforms,字段实例化时返回:不是StringField,而是UnboundField

       rest frawork many=Turn  中的序列化

    __call__
       flask 请求的入口app.run()

        字段生成标签时:字段.__str__ => 字段.__call__ => 插件.__call__

    

       __iter__ 循环对象是,自定义__iter__

        wtforms中BaseForm中循环所有字段时定义了__iter__

    metaclass
        - 作用:用于指定当前类使用哪个类来创建
        - 场景:在类创建之前定制操作
        示例:wtforms中,对字段进行排序。

 

posted @ 2018-04-27 17:31  无名!  阅读(2092)  评论(0编辑  收藏  举报