12

我正在使用 Flask 构建我的 Web 应用程序,并且我想注册一个全局资源,该资源代表与远程服务的连接,该连接持续时间比请求长(在这种情况下,连接是一个有效的 SOAP 连接长达 30 天)。

另一个例子可能是像 MongoDB 这样的数据库,它在驱动程序中处理连接池,如果您在每个请求上创建一个新连接,它的性能就会很差。

应用程序上下文和请求上下文似乎都不适合此任务。

“将另一个对象传递给主烧瓶应用程序”的问题表明我们将此类资源存储在app.config字典中。

4

2 回答 2

5

如果它必须与您的应用程序的实例化一致,那么您应该继承 Flask。如果您所做的只是将资源附加到对象上,考虑到应用程序的创建是一个过程,这真的不会做很多事情。事实是,如果应用程序在实例化期间不需要使用您的资源,您可能不需要这样做。

class MyApp(Flask):
    def __init__(self, *args, **kwargs):
        setattr(self, 'some_resource', SomeResource())
        super(Flask, self).__init__(*args, **kwargs)

app = MyApp(__name__)
app.some_resource.do_something()

除非您有一些特定的用例,否则您最好编写一个包装类,将其转换为烧瓶扩展,在模块级别创建它并将其存储在 app.extensions 中。

class MyExtensions(object):
    def __init__(self, app=None):
        self.app = app
        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        app.extensions['my_extension'] = SomeResource()

app = Flask(__name__)
my_extension = MyExtension(app)

然后您可以选择是否要为每个应用程序提供自己的资源(如上),或者您是否更愿意使用始终指向当前应用程序的共享资源

from flask import _request_ctx_stack
try:
    from flask import _app_ctx_stack
except ImportError:
    _app_ctx_stack = None

stack = _app_ctx_stack or _request_ctx_stack

class SomeResource(object):
    def do_something(self):
        ctx = stack.top
        app = ctx.app
my_resource = SomeResource()
my_resource.do_something()

我认为您不想将其存储在应用程序上下文中,因为“它在 Flask 对象被实例化时开始,并在第一个请求进入时隐式结束”

相反,您希望在模块级别创建资源。然后,您可以将其作为扩展附加到应用程序,或者是的,即使在配置中也是如此 - 尽管使用它进行快速扩展会更加一致和合乎逻辑。

于 2014-02-18T06:16:44.283 回答
1

这是一个 Python 问题,Flask 和其他 Web 框架不允许这样做/使其变得非常困难的原因是因为没有为并发定义的​​内存模型。例如,假设您的网络服务器在它们自己的进程中处理请求(例如 Gunicorn)。这将导致进程分叉主进程,从而复制您的“全局”变量。如果您在 Windows 上运行服务器,那么由于缺少 fork,它将改为创建一个重新导入所有模块的新进程,可能会生成一个干净版本的全局状态,它不记得在主进程 pre 中对其所做的任何更改-线。或者,如果您在名称保护后面声明它,则根本找不到它。

只有两种可能的方法可以始终如一地做到这一点“正确”。一种是专门构建一个 webapp 来保存您的全局状态,并且仅限于单个线程,并让您的其他 webapp 从这个 webapp 调用状态。

二是使用Jython+线程。由于 Jython 在 JVM 中运行,因此它具有定义良好的共享状态内存模型,因此您可以使用所有 Java EE 技巧,如容器管理的并发......

于 2016-09-19T14:54:56.600 回答