zoukankan      html  css  js  c++  java
  • 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中,对字段进行排序。

  • 相关阅读:
    第十一周上机作业
    第十三周作业 张垚
    第十三周上机 张垚
    十二周作业 张垚
    第十二周上机 张垚
    第十一周作业 张垚
    第十一周上机 张垚
    第十周 上机 张垚
    第九周上机 张垚
    第八周 下 张垚
  • 原文地址:https://www.cnblogs.com/ITdong-1/p/10151160.html
Copyright © 2011-2022 走看看