Flask 上下文机制和线程隔离

1. 计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决, 上下文机制就是这句话的体现。

2. 如果一次封装解决不了问题,那就再来一次

上下文:相当于一个容器,保存了Flask程序运行过程中的一些信息 源码:flask/ctx.py

请求上下文:Flask从客户端收到请求时,要让视图函数能访问一些对象,这样才能处理请求,要想让视图函数能够访问请求对象,一个显而易见的方式是将其作为参数传入视图函数,不过这会导致程序中的每个视图函数都增加一个参数,除了访问请求对象,如果视图函数在处理请求时还要访问其他对象,情况会变得更糟。为了避免大量可有可无的参数把视图函数弄得一团糟,Flask使用上下文临时把某些对象变为全局可访问。这就是一种重构设计思路

request 封装了HTTP请求的内容,针对http请求,也是一种符合WSGI接口规范的设计(关于WSGI可参考我对该协议的理解和实现demo mini-wsgi-web),如 request.args.get('user')

session 用来记录请求会话中的信息,针对的是用户信息,如 session['name'] = user.id

应用上下文:应用程序上下文,用于存储应用程序中的变量

current_app 存储应用配置,数据库连接等应用相关信息

g变量 作为flask程序全局的一个临时变量, 充当者中间媒介的作用,我们可以通过它传递一些数据,g保存的是当前请求的全局变量,不同的请求会有不同的全局变量,通过不同的thread id区别

# context locals # 使用代理模式 LocalProxy _request_ctx_stack = LocalStack() _app_ctx_stack = LocalStack() current_app = LocalProxy(_find_app) request = LocalProxy(partial(_lookup_req_object, 'request')) session = LocalProxy(partial(_lookup_req_object, 'session')) g = LocalProxy(partial(_lookup_app_object, 'g')) 1. working outside application context #!/usr/bin/python3 # -*- coding: utf-8 -*- # __author__ = '__JonPan__' from flask import Flask, current_app app = Flask(__name__) a = current_app # is_debug = current_app.config['DEBUG'] @app.route('http://www.likecs.com/') def index(): return '<h1>Hello World. Have a nice day! </1>' if __name__ == '__main__': app.run(host='localhost', port=8888)

报错:

Exception has occurred: RuntimeError

Working outside of application context.

image-20200708104242267

2. flask 上下文出入栈

flask上下文对象出入栈模型图

flask上下文对象出入栈模型图

在应用开发中可用直接引用current_app不会报错,是因为当在一个请求中使用的时候,flask会判断_app_ctx_stack栈顶是否有可用对象,如果没有就会自动推入一个App. 我们获取的current_app就是获取的栈顶元素

# flask/globals.py def _find_app(): top = _app_ctx_stack.top if top is None: raise RuntimeError(_app_ctx_err_msg) return top.app current_app = LocalProxy(_find_app)

修改代码:将app对象推入栈顶

# ... # 将app_context 推入栈中 ctx = app.app_context() ctx.push() a = current_app is_debug = current_app.config['DEBUG'] ctx.pop() # ... # 更有pythonnic的写法 # 将app_context 推入栈中 # with app.app_context(): # a = current_app # is_debug = current_app.config['DEBUG']

Flask 上下文机制和线程隔离

不在出现unbound状态。可正常运行

既然flask会自动帮我们检测栈顶元素是否存在,为什么我们还要做这一步操作,当我们在写离线应用,或者单元测试的时候就需要用到,因为请求是模拟的,不是在application context中的了。

3. python中的上文管理器

实现了__enter__和__exit__方法的对象就是一个上文管理器。

class MyResource: def __enter__(self): print('connect ro resource') return self def __exit__(self, exc_type, exc_value, tb): if tb: print('process exception') else: print('no exception') print('close resource connection') # return True # return False def query(self): print('query data') try: with MyResource() as r: 1/0 r.query() except Exception as e: print(e)

with MyResour ce() as r as 的别名r指向的不是上想问管理器对象,而是__enter__方法返回的值,在以上代码确实是返回了对象本身。

__exit__ 方法 处理退出上下文管理器对象时的一些资源清理工作,并处理异常,三个参数

exc_type 异常类型

exc_value 异常原因解释

tb traceback

__exit__其实是有返回值的,return True表示,异常信息已经在本方法中处理,外部可不接收异常,return False 表示将异常抛出给上层逻辑处理,默认不写返回,即默认值是None, None也表示False

线程隔离机制

Flask 上下文机制和线程隔离

如何实现一个Reqeust 指向多个请求实例,且要区分该实例对象所绑定的用户?

字典:

request = {'key1': val1, 'key2': val2}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdpww.html