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中,對字段進行排序。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM