深入剖析python flask中的线程隔离

线程隔离思想
  • 原理是使用字典来保存数据

  • 当然我们还要操作数据,我们把线程隔离的数据封装到一个对象,这样我们在外部直接使用该对象的相关方法就可以了

  • flask中引用werkzeug库,里面有个local模块,这个模块下面有个Local对象, flask做线程隔离的实质就是由Local对象完成的,Local对象的本质就是字典的方式实现线程隔离的,是对线程id字典的一个封装

  • Local是一个线程隔离的对象,相关属性的操作不同线程之间是互相不影响的,保存了线程之间的独立,

import threading

from werkzeug.local import Local

my_obj = Local()

my_obj.b = 1

def worker():

    # 新线程

    my_obj.b = 2

    print('in new thread b is:' + str(my_obj.b))

new_t = threading.Thread(target=worker, name='new-thread')

new_t.start()

print('in main thread b is:', my_obj.b)

执行结果:

in new thread b is:2

in main thread b is: 1

线程隔离的栈

  • image.png
  • LocalStack()是一个线程隔离的对象,可以用来做线程隔离的栈,使用Local()对象实现,LocalStack和Local都是可以单独使用的额,不需要依赖于flask,都是单独的库,和flask之间没有直接的关系

  • LocalStack,Local,字典之间的关系

  • Local使用字典的方式实现的线程隔离,而LocalStack封装了Local对象,把Local对象作为它的一个属性,从而实现了一个线程隔离的栈结构

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

  • 编程也是一种艺术,编码要含蓄

LocalStack的使用

  • Local可以当做一个普通对象,通过点来操作,而LocalStack必须要使用它定义的push,pop,top来操作
# -*- coding: utf-8 -*-

from werkzeug.local import LocalStack

s = LocalStack()

s.push(1)

print(s.top)

print(s.top)

print(s.pop())  # pop()删除最后入栈的一个元素,并返回

print(s.top)

s.push(1)

s.push(2)

print(s.top)

print(s.top)

print(s.pop())

print(s.top)

执行结果:

1

1

1

None

2

2

2

1
  • 栈,后进先出,只能取栈顶元素,数据结构就是限制了某些能力
# -*- coding: utf-8 -*-

import threading

from werkzeug.local import LocalStack

my_stack = LocalStack()

my_stack.push(1)

print('in main thread after push ,value is ' + str(my_stack.top))

def worker():

    # 新线程

    print('in new thread before push ,value is ' + str(my_stack.top))

    my_stack.push(2)

    print('in new thread before push ,value is ' + str(my_stack.top))

new_t = threading.Thread(target=worker, name='new-thread')

new_t.start()

print('finally, in main thread ,value is ' + str(my_stack.top))

执行结果:

in main thread after push ,value is 1

in new thread before push ,value is None

in new thread before push ,value is 2

finally, in main thread ,value is 1
flask中的LocalStack
  • image.png
  • 用来隔离应用上下文,请求上下文, 在多线程中,每个线程都会创建对象,如果不隔离的话,很容易发生混淆,容易造成程序错误

  • flask中被线程隔离的对象,Request,request,g, session

  • image.png
线程隔离对象
  • 线程隔离对象:Local,LocalStack

  • 被线程隔离的对象: AppContext, RequestContext

  • Request是位于RequestContext的内部,所以它是一个间接是实现的线程隔离

  • AppContext和flask核心对象app是两个对象,一定不要混淆,flask的核心对象app作为一个属性存在于AppContext下

  • flask的核心对象在全局中只有一个,current_app便是flask的核心对象app,全局只有一个,所以对于current_app来说,线程隔离是没有意义的

  • 如果所有的用户,所有的请求都共享同一份数据,可以考虑将数据爆保存到app上来,比如网站的访问计数,当然,这个存在线程安全的问题

  • image.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容