C10K problem告诉我们传统的网络服务器最多只能达到约10k的自然限制。
像nginx这样的服务器使用单线程模型和异步通信而不是线程来处理传入的请求。 AFAIK Gevent使用greenlets(同一线程内的可切换执行上下文)而不是线程。
这引出了两个问题(再次:假设我们处于异步模型中 - 想想gevent和gunicorn):
Django还有一个问题:
threading.local
(在自定义中间件中填充)来识别当前线程的不良做法,但在那段时间我没有考虑非线程架构(只要我能说“我的代码就好了”一个请求(暗示)一个线程“)。这可以帮助我:在一个名为(我的/自定义)字段的request
方法的表单中识别当前clean()
(即根据当前请求验证数据的值)。但是,如果我有超过10k限制的同时请求并使用异步(非线程)方法,则此方法将失败。
答案 0 :(得分:3)
( EDIT - gevent.monkey.patch_all() - 在wsgy.py脚本文件中运行 - 自动修补threadlocals以成为greenlet本地,因此GEvent(或带有Gevent的GUnicorn)不需要使用Werkzeug的替代方案工人) - 如果,不知何故,你使用没有GEvent的greenlets,你可能需要这个解决方案)
在记住Flask Framework时,我发现自己是一个答案:
Flask是一个支持"全球"许多对象,例如session
和request
,其中"看起来"比如threading.local
个对象。主要区别在于它们是上下文本地而不是线程本地,而上下文是任何当前执行堆栈。
一个线程拥有它自己的上下文(因此在阅读线程理论时,上下文切换的概念)。一个进程有它的上下文,它包含线程(和一个主线程)。
到目前为止,在我们所知的理论中,一个进程包含一个线程,一个线程包含它自己的执行上下文。除非线程可以创建自己的数据上下文,否则数据始终是共享的。这是线程本地(变量/数据)概念出现的地方。
但是为了解决这个并发执行的概念,并考虑到C10K问题,首选一个线程中的异步执行而不是多个阻塞线程与相应的Context Switch(特别是关于python,我们在默认的python中有GIL) distr0)。 Greenlet创建为同一线程切换上下文,现在层次结构发生了变化:
Process 1--* thread 1--* greenlet (and now the requests are here)
所以Greenlets的概念是在像Gevent这样的服务器中用Python创建和实现的,你不能再使用线程本地数据,因为请求不再绑定到线程(即它们可以共享相同的threadlocal上下文,赛车数据)。
现在上下文本身就是greenlet,我们需要一个本地化的概念而不是线程本地化。
那么:Flask如何使用本地上下文隔离每个请求的数据? (例如会话,请求)。上下文无关的隔离的答案在这里:
Werkzeug和Flask拥有相同的创造者。 Werkzeug 不一个框架,但只是可以在任何WSGI框架中使用的一组实用程序(例如 Django )。框架本身就是Flask,它实际上依赖于Werkzeug的实用程序。
Werkzeug的上下文本地有助于创建(正确地说)上下文本地(上下文意味着线程,请求或进程 - 取决于服务器如何调度请求),这可以帮助我们存储greenlet-具体数据并避免使用threadlocals:
#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