其他分享
首页 > 其他分享> > flask 3 上下文管理、threading.local相关、基础知识

flask 3 上下文管理、threading.local相关、基础知识

作者:互联网

Flask day3 上下文管理、threading.local相关、基础知识

内容回顾

1.Linux命令

cd
vim
mkdir
ls
touch
cat
sed

2.面向对象:特殊方法

obj['x']=123  # 会执行__setitem__方法
obj.x=123  # 会执行setattr方法
obj + 123

3.functools

# 自动传参
from functools import partial

def func(a, b, c):
    return a + b + c


v1 = func(10, 20, 3)
print(v1)

new_func = partial(func, 10, 20)

v2 = new_func(3)
print(v2)

4.认识的装饰器?应用场景

应用:
	-flask:路由、brfore_request
	-django:csrf,缓存,用户登录

5.Flask

  1. 蓝图
  2. session原理

今日内容

1.threading.local

作用:为每个线程开辟一块空间进行数据存储

from threading import local
from threading import Thread
from threading import get_ident
import time

# 特殊的对象,让对象之间相互独立
obj = local()
# obj = -1

def task(arg):
    # 对象.value = 1/2/3/4/5
    print(get_ident())
    obj.value = arg
    time.sleep(2)
    print(obj.value)


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

>>>>>>>>
3920
11004
740
9880
7396
13304
10220
10492
7928
6904


自己通过字典创建一个类似于threading.local的东西

1.函数方式

{
    3920:{val1:0}
    11004:{val1:1}
    740:{val1:3}
    9880:{}
    7396:{}
}



storage = {}


def set(k, v):
    ident = get_ident()
    if ident in storage:
        storage[ident][k] = v
    else:
        storage[ident] = {k: v}

def get(k):
    ident = get_ident()
    return storage[ident][k]

def task(arg):
    set('val', arg)
    print(storage)
    time.sleep(2)
    v = get('val')
    print(v)


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

2.面向对象方式

class Local:
    def __init__(self):
        self.storage = {}

    def __setattr__(self, k, v):
        ident = get_ident()
        if ident in self.storage:
            self.storage[ident][k] = v
        else:
            self.storage[ident] = {k: v}

    def __getattr__(self, k):
        ident = get_ident()
        return self.storage[ident][k]


"""
由于实例化时会自动调用Local中的__init__方法,执行self.storage ={}
而self.storage ={}则会自动执行__setattr__方法
会先获取ident = get_ident()然后走else分支self.storage[ident] = {k: v}!!!此时又有self.storage又会再次执行__setattr__所有会进入死循环
最终报错
"""
obj = Local()

def task(arg):
    obj.val = arg
    print(obj.storage)
    time.sleep(2)
    print(obj.val)


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

3.面向对象优化

class Local:
    def __init__(self):
        object.__setattr__(self, 'storage', {})

    def __setattr__(self, k, v):
        ident = get_ident()
        if ident in self.storage:
            self.storage[ident][k] = v
        else:
            self.storage[ident] = {k: v}

    def __getattr__(self, k):
        ident = get_ident()
        return self.storage[k][item]


"""
由于实例化时会自动调用Local中的__init__方法,执行self.storage ={}
而self.storage ={}则会自动执行__setattr__方法
会先获取ident = get_ident()然后走else分支self.storage[ident] = {k: v}!!!此时又有self.storage又会再次执行__setattr__所有会进入死循环
最终报错
解决方法,初始化时调用父类object去创建storage的空字典
"""
obj = Local()


def task(arg):
    obj.val = arg
    print(obj.storage)
    time.sleep(2)
    print(obj.val)


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

优于threading.local地方

可以为每个线程(协程)开辟一块空间进行数据存储

try:
    from greenlet import getcurrent as get_ident
except Exception:

    from threading import get_ident
import time
from threading import Thread

class Local:
    def __init__(self):
        object.__setattr__(self, 'storage', {})

    def __setattr__(self, k, v):
        ident = get_ident()
        if ident in self.storage:
            self.storage[ident][k] = v
        else:
            self.storage[ident] = {k: v}

    def __getattr__(self, k):
        ident = get_ident()
        return self.storage[ident][k]

2.上下文管理

# 在源码中分析上下文管理
第一阶段:
	-将ctx(request,session)放到"空调"上(Local对象)

第二阶段:
	-将视图函数导入:request/session
第三阶段:
	-请求处理完毕
		-获取session并保存到cookie
    	-将ctx删除

image

# flask中session是什么时候产生什么时候销毁的
当请求进来时,会将request和session封装成一个RequestContext对象,该对象 通过localstack放入内部的local对象中此时session是None值,接着执行open_session将cookie中值拿来放入session中
最后返回时执行save_session将ctx中的读出来进行序列化写入cookie,最后pop将ctx去除

视图阶段的上下文管理

from flask import Flask, request, session

app = Flask(__name__)


@app.route('/')
def hello_world():
    """
    request = LocalProxy(partial(_lookup_req_object, "request"))
    session = LocalProxy(partial(_lookup_req_object, "session"))
    def _lookup_req_object(name):
    # name = request/session
    # top = ctx(request,session)
    top = _request_ctx_stack.top
    if top is None:
        raise RuntimeError(_request_ctx_err_msg)
    # 从ctx中获取name对象  request/session
    return getattr(top, name)


    """
    print(request)  # LocalProxy.__str__
    print(request.method)  # LocalProxy.__getattr__(key="method")  # 先去ctx中获取request,再去request中获取method
    print(request.args)  # LocalProxy.__getattr__(key="args")  # 先去ctx中获取request,再去request中获取args

    session['k1'] = 123  # LocalProxy.__setattr__(key="k1")  # 先去ctx中获取session,再去session中给k1设置值
    print(session['k1'])  # LocalProxy.__getattr__(key="k1")  # 先去ctx中获取session,再去session中获取args

    """
    class LocalProxy(object):
        def __init__(self, local, name=None):
        # self.__local = 函数
        object.__setattr__(self, "_LocalProxy__local", local)
        object.__setattr__(self, "__name__", name)
        if callable(local) and not hasattr(local, "__release_local__"):
            # "local" is a callable that is not an instance of Local or
            # LocalManager: mark it as a wrapped function.
            object.__setattr__(self, "__wrapped__", local)
        def __getattr__(self, name):
            if name == "__members__":
                return dir(self._get_current_object())
            # name = method
            # obj = self._get_current_object()  去ctx中获取request
            # return getattr(obj, name)  request.method
            return getattr(self._get_current_object(), name)
        
        def _get_current_object(self):
            if not hasattr(self.__local, "__release_local__"):
                return self.__local()
            try:
                return getattr(self.__local, self.__name__)
            except AttributeError:
                raise RuntimeError("no object bound to %s" % self.__name__)
    """


    return 'hello world'



if __name__ == '__main__':
    app.run()



"""
用户请求一旦到来请求:
    1.app.__call__=========>def __call__(self, environ, start_response):
                                return self.wsgi_app(environ, start_response)
    其中environ是由wsgi操作完封装好的
    2.ctx = self.request_context(environ):RequestContext(self, environ)==========>就是一个团队,内有request和session
        -ctx.request = Request(environ) = request
        -ctx.session = None
        -路由匹配
"""

image

一个请求的完整流程

image

问题:flask中共有几个LocalStack和Local对象

都是两个

g是什么

是每一次请求的全局变量,在该次请求结束后销毁,可在before_request中给g赋值,在该次请求后面的操作中可以用该变量去取值

标签:__,ident,flask,request,self,storage,threading,session,local
来源: https://www.cnblogs.com/HinaChan/p/14705039.html