• flask线程隔离技术


    1
    多个线程操作同一对象带来的问题

     

    多个线程修改同一对象属性,会造成数据错乱。

     

    import timeimport threading

    class A: b = 1

    obj1 = A()

    def worker(): obj1.b = 2

    t1 = threading.Thread(target=worker)t1.start()time.sleep(1)print(obj1.b)

     

    输出结果:

     

    2

     

    2

    如何做到线程隔离?

     

    """Local是被线程隔离的对象"""import timeimport threadingfrom werkzeug.local import Local

    obj1 = Local()obj1.b = 1

    def worker(): obj1.b = 2 print("子线程中obj1.b的值为{}".format(obj1.b))

    t1 = threading.Thread(target=worker)t1.start()time.sleep(1)print("主线程中obj1.b的值为{}".format(obj1.b))

     

    输出结果:

     

    子线程中obj1.b的值为2主线程中obj1.b的值为1

     

    所以,凡是继承了Local的,都是线程隔离的

     

    3
    Local实现线程隔离的方法

     

    阅读源码文件,local.py

     

    def __setattr__(self, name, value): ident = self.__ident_func__() # 取当前线程的线程ID号 storage = self.__storage__# 操作字典,把线程id号作为key保存起来try: storage[ident][name] = value except KeyError: storage[ident] = {name: value}

     

    原来,Local是通过字典这种python中的数据结构实现的线程隔离。每一个线程都有对应的自己的线程ID, 并将对象作为value存放。如:{线程ID1:对象, 线程ID2:对象}

     

    4

    flask的线程隔离栈 LocalStack

     

    阅读flask源码文件globals.py文件

    # context locals_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'))

     

    发现请求上下文(_request_ctx_stack) 和 应用上下文 (_app_ctx_stack) 都是LocalStack类的对象。LocalStack这个单词可以分为Local和Stack两个部分,顾名思义LocalStack:是封装Local实现线程隔离的栈结构。如下代码可以验证LocalStack是一个线程隔离的栈结构:

     

    # LcoalStack线程隔离的栈import timeimport threadingfrom werkzeug.local import LocalStackmy_stack = LocalStack()my_stack.push(1)print("主线程中,栈顶元素为{}".format(str(my_stack.top)))def worker(): print("在push之前,子线程中的栈顶元素为{}".format(str(my_stack.top))) my_stack.push(2) print("在push之后,子线程中的栈顶元素为{}".format(str(my_stack.top)))t1 = threading.Thread(target=worker)t1.start()time.sleep(1)print("最后,主线程中的栈顶元素为{}".format(str(my_stack.top)))

     

    输出结果:

     

    主线程中,栈顶元素为1在push之前,子线程中的栈顶元素为None在push之后,子线程中的栈顶元素为2最后,主线程中的栈顶元素为1

     

    5
    flask线程隔离技术

     

    由之前写过的文章得知current_app、request、session、g等对应都是指向相应栈的栈顶,当我们接受到一个请求里,flask才会把相应的app对象和新创建的Request对象压入相应的栈。由此,我们就知道了flask是怎么实现的多个请求,request的线程隔离。最后总结一下,字典、Local、LocalStack三者的关系,Local使用字典的方式实现的线程隔离,LocalStack封装了Local对象,并把它作为了自己的一个属性,从而实现了线程隔离的栈结构

     

     
  • 相关阅读:
    作品-网站-[原生开发]云鸽信息网
    ASYNC_NETWORK_IO和PREEMPTIVE_OS_WAITFORSINGLEOBJECT等待事件
    还原一直卡在ASYNC_IO_COMPLETION浅析
    B树之C语言实现(包含查找、删除、插入)
    Asp.Net Core 禁用预编译
    ASP.NET Core Razor 视图组件
    WITH RECOMPILE 和 OPTION(RECOMPILE) 使用上的区别
    如何减少SQL Server中的PREEMPTIVE_OS_WRITEFILEGATHER等待类型
    WITH RECOMPILE和OPTION(RECOMPILE)区别
    SQL Server PageIOLatch和PageLatch
  • 原文地址:https://www.cnblogs.com/lirunsheng/p/10838947.html
Copyright © 2020-2023  润新知