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对象,并把它作为了自己的一个属性,从而实现了线程隔离的栈结构

 

 
原文地址:https://www.cnblogs.com/lirunsheng/p/10838947.html