一、引入:

在无线程隔离情况下,通过线程调用函数,函数内部改变传入对象的属性值(排除非线程安全情况),都将更改传入的对象属性

 1 import threading
2
3 class TestThread:
4 value = 1
5
6 s = TestThread()
7
8 def test1():
9 s.value = 2
10
11 thread = threading.Thread(target=test1)
12 thread.start()
13
14 print(s.value)
15
16 # 2

二、Local对象

1. 使用线程隔离的意义:使当前线程能够正确引用到它自己创建的对象,而不是引用到其他线程所创建的对象。
2. 在利用flask进行WEB开发中,一定有多个请求进入服务器,那如果只实例化一个request对象并指向多个请求,那就无法获得其中任何一个请求信息。因此,flask采用线程隔离栈LocalStack对象来进行线程隔离。
3. 了解LocalStack就需要先了解Local对象。简单来说,这个Local对象内部通过字典的形式,将每个线程的id作为key,请求对象信息作为value。这样,由于每个线程id号不同,自然也就可以拿到每个线程的请求信息。以下是使用Local类做的小测试:

 1 import threading
2 from werkzeug.local import Local
3
4 s = Local()
5 s.value = 1
6
7 def test1():
8 s.value = 2
9 print("新线程的value: %d" % s.value)
10
11 thread = threading.Thread(target=test1)
12 thread.start()
13
14 print("主线程中的value: %d" % s.value)
15
16 # 新线程的value: 2
17 # 主线程中的value: 1

三、Flask中的线程隔离栈

Local使用字典的方式实现线程隔离,LocalStack封装Local对象实现了线程隔离的栈结构。这两者在使用上的区别是:使用Local对象时,可以直接像面向对象取属性一样操作,LocalStack需要进行top操作取栈顶元素(因为它毕竟是一个栈),下面是LocalStack部分源码,可以看到它内部实现了栈的一些基本操作

 1 class LocalStack:
2 """This class works similar to a :class:`Local` but keeps a stack
3 of objects instead. This is best explained with an example::
4
5 >>> ls = LocalStack()
6 >>> ls.push(42)
7 >>> ls.top
8 42
9 >>> ls.push(23)
10 >>> ls.top
11 23
12 >>> ls.pop()
13 23
14 >>> ls.top
15 42
16
17 They can be force released by using a :class:`LocalManager` or with
18 the :func:`release_local` function but the correct way is to pop the
19 item from the stack after using. When the stack is empty it will
20 no longer be bound to the current context (and as such released).
21
22 By calling the stack without arguments it returns a proxy that resolves to
23 the topmost item on the stack.
24
25 .. versionadded:: 0.6.1
26 """
27
28 def __init__(self) -> None:
29 self._local = Local()
30
31 def __release_local__(self) -> None:
32 self._local.__release_local__()
33
34 def __call__(self) -> "LocalProxy":
35 def _lookup() -> t.Any:
36 rv = self.top
37 if rv is None:
38 raise RuntimeError("object unbound")
39 return rv
40
41 return LocalProxy(_lookup)
42
43 def push(self, obj: t.Any) -> t.List[t.Any]:
44 """Pushes a new item to the stack"""
45 rv = getattr(self._local, "stack", []).copy()
46 rv.append(obj)
47 self._local.stack = rv
48 return rv
49
50 def pop(self) -> t.Any:
51 """Removes the topmost item from the stack, will return the
52 old value or `None` if the stack was already empty.
53 """
54 stack = getattr(self._local, "stack", None)
55 if stack is None:
56 return None
57 elif len(stack) == 1:
58 release_local(self._local)
59 return stack[-1]
60 else:
61 return stack.pop()
62
63 @property
64 def top(self) -> t.Any:
65 """The topmost item on the stack. If the stack is empty,
66 `None` is returned.
67 """
68 try:
69 return self._local.stack[-1]
70 except (AttributeError, IndexError):
71 return None

那么也可以手动调用LocalStack加深印象:

 1 import threading
2 from werkzeug.local import LocalStack
3
4 stack = LocalStack()
5 stack.push(1)
6 print("新线程push前,主线程的栈顶: %d" % stack.top)
7
8 def test():
9 print("新线程的栈顶: %s" % stack.top)
10 stack.push(2)
11 print("新线程push后新线程中的栈顶: %d" % stack.top)
12
13 thread = threading.Thread(target=test)
14 thread.start()
15
16 print("最终主线程的栈顶: %d" % stack.top)
17
18 # 新线程push前,主线程的栈顶: 1
19 # 新线程的栈顶: None
20 # 新线程push后新线程中的栈顶: 2
21 # 最终主线程的栈顶: 1

由此可见,每创建一个线程,该线程都会有自己的一个LocalStack来实现线程隔离

四、flask中的app和request

我们知道,flask中存在两个上下文对象(AppContext和RequestContext),flask核心对象app存放在AppContext中,请求信息Request存放在RequestContext中,那么既然Request是被线程隔离的对象(因为每次请求都需要保存当前线程的信息),app是否是被线程隔离的对象呢?
答案是否定的,核心对象app是在flask程序主入口文件创建的,也就是只有第一次请求服务器开启,会创建一个app,之后的请求都不会进入主入口文件,那么app也就不会重复创建,所以如果将app也进行线程隔离,这么做也没有太大意义。

最新文章

  1. 深入理解闭包系列第三篇——IIFE
  2. c#关于类的继承
  3. Android drawable微技巧
  4. js分秒必争
  5. java12-6 冒泡排序法和选择排序法
  6. varnish4.0简介
  7. javascript知识点记录(2)
  8. iOS中关于KVC与KVO知识点
  9. 《Android开发艺术探索》读书笔记 (2) 第2章 IPC机制
  10. c# sqlserver备份还原(转)
  11. HTML、CSS、JS、PHP 的学习顺序~(零基础初学者)
  12. STL部分的实现
  13. java利用接口和适配器进行完全解耦--参考《thinking in java》
  14. 批量删除ppt动画
  15. stylus笔记(三)
  16. pat--7-11 出栈序列的合法性(25 分)
  17. codevs1735 方程的解数(meet in the middle)
  18. 《Python》 列表、元祖和range
  19. CSS的outline属性
  20. 类中的迭代器__iter__

热门文章

  1. 12月7日内容总结——jQuery查找标签、操作标签、事件和动画效果,Bootstrap页面框架的介绍和使用讲解
  2. 快速入门API Explorer
  3. activiti03 SSM使用activity
  4. vue @click的stop和prevent
  5. SpringMVC的类型转换器与RESTFUL集成
  6. 郁金香-了解MFC信息机制
  7. 【KAWAKO】soundtoch-使用可执行文件对音频进行变调或变速
  8. 有趣的python库-pyttsx3
  9. AC 自动机上 DP
  10. CSS transform: scale()