前言
本文紧接着「Flask 源码剖析 (三):Flask 的上下文机制 (上)」,讨论如下问题。
1.Python 中有 thread.local 了,werkzeug 为什么还要自己弄一个 Local 类来存储数据?
2. 为什么不构建一个上下文而是要将其分为请求上下文 (request context) 和应用上下文 (application context)?
3. 为什么不直接使用 Local?而要通过 LocalStack 类将其封装成栈的操作?
4. 为什么不直接使用 LocalStack?而要通过 LocalProxy 类来代理操作?
回顾 Flask 上下文
在上一篇文章中,详细讨论了 Flask 上下文机制,这里简单回顾一下。
所谓 Flask 上下文,其实就是基于 list 实现的栈,这个 list 存放在 Local 类实例化的对象中,Local 类利用线程 id 作为字典的 key,线程具体的值作为字典的 values 来实现线程安全,使用的过程就是出栈入栈的过程,此外,在具体使用时,会通过 LocalProxy 类将操作都代理给 Local 类对象。
为何需要 werkzeug 库的 Local 类?
treading 标准库中已经提供了 local 对象,该对象实现的效果与 Local 类似,以线程 id 为字典的 key,将线程具体的值作为字典的 values 存储,简单使用如下。
In [1]: import threading
In [2]: local = threading.local()
In [3]: local.name = '二两'
In [4]: local.name
Out[4]: '二两'
那为何 werkzeug 库要自己再实现一个功能类似的 Local 类呢?
主要原因是为了兼容协程,当用户通过 greenlet 库来构建协程时,因为多个协程可以在同一个线程中,threading.local 无法处理这种情况,而 Local 可以通过 getcurrent () 方法来获取协程的唯一标识。
# werkzeug/local.py
# since each thread has its own greenlet we can just use those as identifiers
# for the context. If greenlets are not available we fall back to the
# current thread ident depending on where it is.
try:
from greenlet import getcurrent as get_ident
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident
为什么要将上下文分为多个?
回顾一下问题。
为什么不构建一个上下文而是要将其分为请求上下文 (request context) 和应用上下文 (application context)