(EDIT - gevent.monkey.patch_all() - 在 wsgy.py 脚本文件中运行 - 自动修补 threadlocals 以成为 greenlet locals,因此 GEvent(或 GUnicorn 与 Gevent 工作人员)不需要使用 Werkzeug 的替代方案 - 如果,不知何故,你在没有 GEvent 的情况下使用 greenlets,你可能需要这个解决方案)
当我想起Flask 框架时,我找到了答案:
Flask 是一个框架,它支持“全局”许多对象session
,并且request
“看起来”像threading.local
对象。主要区别在于它们是上下文局部变量而不是线程局部变量,上下文是任何当前的执行堆栈。
线程有自己的上下文(因此在阅读线程理论时会有上下文切换的概念)。一个进程有它的上下文,它包含线程(和一个主线程)。
到目前为止,在我们所知道的理论中,一个进程包含一个线程,一个线程包含它自己的执行上下文。除非线程可以创建自己的数据上下文,否则数据始终是共享的。这是线程本地(变量/数据)概念出现的地方。
但是为了解决并发执行的概念,并考虑到 C10K 问题,一个线程中的异步执行是首选,而不是多个阻塞线程和相应的上下文切换(特别是关于 python,我们在默认的 python distr0 中有 GIL)。Greenlet 是作为同线程切换上下文创建的,现在层次结构发生了变化:
Process 1--* thread 1--* greenlet (and now the requests are here)
所以Greenlets的概念是在像Gevent这样的服务器中用Python创建和实现的,你不能再使用线程本地数据,因为请求不再绑定到线程(即它们可以共享相同的线程本地上下文,竞争数据)。
现在上下文本身就是greenlet,我们需要上下文本地而不是线程本地的概念。
那么:Flask 如何使用本地上下文来隔离每个请求的数据?(例如会话、请求)。上下文无关隔离的答案在这里:
Werkzeug 的上下文局部变量
Werkzeug 和 Flask 具有相同的创建者。Werkzeug不是一个框架,而只是一组可以在任何 WSGI 框架(例如Django)中使用的实用程序。框架本身就是 Flask,它实际上依赖于 Werkzeug 的实用程序。
Werkzeug 的上下文局部变量有助于创建(正确地说)上下文局部变量(上下文表示线程、请求或进程 - 取决于服务器如何分派请求),这可以帮助我们存储特定于 greenlet 的数据并避免使用线程本地化:
#a python module for my django project where I define
#a custom field class which statically needs to know the
#current request.
#I was using, instead, a threadlocal. The usage is THE SAME.
#the main difference is that threads are GCed, while contexts
#not necessarily, so you must ALWAYS release them explicitly
#using release_local, for the current context.
#this code below used to have `threading.local` instances
#instead of `werkzeug.local.Local` instances.
#as I said before, assigning data works like before, but
#the main difference is when releasing the data.
from werkzeug.local import Local, release_local
class AutocompleteField(object):
DATA = Local()
@staticmethod
def set_request(request):
AutocompleteField.DATA.request = request
@staticmethod
def unset_request(request):
release_local(AutocompleteField.DATA)
@staticmethod
def get_request():
try:
return AutocompleteField.DATA.request
except AttributeError as e:
return None