Fork me on GitHub

Flask 上下文管理-- (session,request,current_app的传递)--类似本地线程实现,以及多app应用

Flask session,request,current_app的传递

请求上下文的作用 -- 封装请求相关得数据(request,session)

  请求上下文

	request
	session

	request local类 {线程,协程的唯一ID:{stack:[RequestContext(request,session)]}} 

  应用上下文

	app local类 {线程,协程的唯一ID:{stack:[AppContext(app,g)]}} 
            
               # app 保存着 应用相关的值
               # g  每次请求周期都会创建一个用于在请求周期中传递值 的 容器

1 flask的 request, session 和 current_app 都是 设置方式比较新颖 -- 通过上下文管理的方式实现的

类似于本地线程 threading_local ,创建Local类

local = {
        '线程或者协程的唯一标识':{'stack':[RequestContext(),]},  # a   每个线程一份
        '线程或者协程的唯一标识':{'stack':[RequestContext(),]},  # b
        '线程或者协程的唯一标识':{'stack':[RequestContext(),]},  # c
        '线程或者协程的唯一标识':{'stack':[RequestContext(),]},  # d
        '线程或者协程的唯一标识':{'stack':[RequestContext(),]},  # e

        }

    每次请求进来app.run调用 call 方法, 将包含了所有请求相关数据的实例对象RequestContext()添加, 通过stack(键),push到一个地方Local中,使用的时候再去取(top方法取值),在请求结束后返回的时候  pop 掉

与Django的区别

请求相关数据的传递方式 :                                                
    
    Django  
        参数一个一个传递
    
    Flask
        基于Local(类似于本地线程)和LocalStack(push, pop, top)完成
        参数不用来回传递, 直接获取reqeust
    
    多个请求一起数据也不会混淆
    
        单线程 - - 每次只能有一个请求处理
        多线程 - -  通过Local实现不同的数据划分 - -   thread - -线程的唯一标识
        协程 - -     greenlet - - 协程的唯一标识

flask 的上下文管理机制描述

(1)	与django相比是两种不同的方式实现:

  	django/tornado 是通过传参的方式

	flask 第通过上下文管理机制

	两种都可以实现,只是实现的方式不一样

(2)类似 threading local 机制,
     flask创建  一个local类 {线程,协程的唯一ID:{stack:[RequestContext(request,session)]}}  保证数据隔离

 		请求进来 把ReqeustContext对象 push到 对应的stack中
 		使用 的时候 通过localstack的top方法,获取local中的reqeust
 		请求终止  通过localstack pop方法,删除local的request

2 补充 partial 函数

其实就是函数调用的时候,有多个参数 参数,但是其中的一个参数已经知道了,我们可以通过这个参数重新绑定一个新的函数,然后去调用这个新函数。

from functools import partial

def f(a,b):
    return a + b

f1 = partial(f,10)

print(f1(5))
-->> 15

3 唯一标识

基于 Local类

类似于本地线程theading_local  -->> 每一个线程 创建一个

from greenlet import getcurrent as get_ident
可以基于 greenlet -->> 粒度更细

        比如 wsgi  -- 有基于线程的,也有基于协程实现的


本地线程:
                

    import threading

    local_values = threading.local()


    def func(num):
        local_values.name = num
        import time
        time.sleep(1)
        print(local_values.name, threading.current_thread().name)


    for i in range(20):
        th = threading.Thread(target=func, args=(i,), name='线程%s' % i)
        th.start()

4 多app应用,以及web'访问多app时的上下文

多app应用,通过前缀做分发

from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.serving import run_simple

app1 = Flask('app1')
app2 = Flask('app2')

@app1.route('/index')
def index():
	return 's'

@app2.route('/index')
def index():
	return 's'

dm = DispatcherMiddleware(app1,{'/app2':app2})

if __name__ == '__main__':
	run_simple('localhost',5000,dm)


同时并发的请求 app1 和 app2,请求上下文Local类中 {
    'ID app1':{stack:[ReqeustContext,]},
    'ID app2':{stack:[ReqeustContext,]},
}

5 补充 with .. 上下文管理

class SQLHelper(object):

	def __enter__(self):
		print('开始')
		self.open()
		return self

	def open(self):
		pass

	def fetch(self):
		pass

	def close(self):
		pass

	def __exit__(self, exc_type, exc_val, exc_tb):
		print('结束')
		self.close()


with SQLHelper() as f:
	pass

6 为什么 flask的 local 保存数据要使用 列表建成的栈

#  如果是 web 程序,栈中永远是 一条数据 (可以不使用栈)
#  如果是 脚本测试 出现如下的上下文嵌套 ,会出现 多条数据

from flask import Flask,current_app,_app_ctx_stack

app1 = Flask(__name__)
app1.config['DEBUG'] = True

app2 = Flask(__name__)
app2.config['DEBUG'] = False


with app1.app_context():
    print(_app_ctx_stack._local.__storage__)
    print(current_app.config['DEBUG'])  # current_app  _app_ctx_stack.top [-1]

    with app2.app_context():
        print(_app_ctx_stack._local.__storage__)
        print(current_app.config['DEBUG'])

                #  {5116: {'stack': [<flask.ctx.AppContext object at 0x00000000038C55C0>, <flask.ctx.AppContext object at 0x00000000038C5748>]}}     False
posted @ 2018-03-11 18:00  派对动物  阅读(1900)  评论(0编辑  收藏  举报
Top