【问题标题】:Flask - Store values in memory between requestsFlask - 在请求之间将值存储在内存中
【发布时间】:2015-07-14 13:10:01
【问题描述】:

我有一个单页应用程序 - 前端是 Angularjs,后端是烧瓶,它允许用户上传文件(xlsx、csv...),然后交互式地分析/查询文件

基本上用户在第一次上传时将文件加载到内存中,然后后续的 ajax 调用将在内存中访问该文件。我不确定如何在后续请求(ajax)之间将文件保存在内存中。

g 变量在每次请求后都会被删除,如果我理解用于跨请求访问值的权利(通常由 before_request 设置并且可通过 views 全部使用)

请求上下文是请求本地的。我确实设法在 current_app 上设置了值,然后能够在我随后的 ajax 调用中访问它

# On my first file upload, i load the file into memory
and set it to a variable on current_app:

from flask import current_app
@app.route('/upload', methods =['POST'])
def upload():
   ...
   upload file into memory
   ...
   current_app.file = file_in_memory



@app.route('/subsequent_call')
def subsequent():
    # i'm able to access the file in memory through 
    the current_app.file which i set earlier

    return current_app.file.number_of_lines()

这种将文件存储在 current_app 内存中的方法看起来并不正确,而且感觉太脏/太黑了。这会扩大规模吗?

我可以在每次请求后腌制文件并在每次请求时将其拉回。但是,当用户以交互方式查询数据时,每次都将文件存储/酸洗和重新提取到内存中似乎过于繁重/效率低下

还有其他优雅/正确的方法可以做到这一点,app_context,werkzeug locals 等吗?还是我想的都错了?

【问题讨论】:

  • 在 Web 服务器上存储状态是非常糟糕的做法。为什么它需要在内存中?
  • @Jharris:同意网络服务器存储状态。当我将文件加载到熊猫对象中时,该文件需要在内存中。在请求之间腌制 pandas 对象感觉有点太低效了。
  • 例如,当您使用显式进程池时。当然,我可以将所有内容存储在数据库中,但在某些特定情况下使用内存会更有效。

标签: python ajax rest flask python-requests


【解决方案1】:

如果您的网络服务器产生多个进程(工作人员)来处理请求,那么以这种方式存储文件是行不通的,而这正是大多数生产服务器的工作方式。

如果您的服务器负载增加,进一步将文件对象保存在内存中不会扩展,您可以将文件保存在文件系统中并在每次请求期间初始化 pandas 对象。您可以将此与加载腌制对象进行比较,看看哪个更快。您还必须考虑酸洗的开销,而不仅仅是解酸。

编辑:解释为什么它不能在生产中工作

Gunicorn 和类似的网络服务器可能会产生多个工作人员,除非您在配置中进行限制,工作人员本质上是一个单独的进程,每个进程都有自己的 python 执行环境。因此,假设您的第一个请求命中 worker1,并且您在该过程中创建了一个变量 current_app.file = file_in_memory。然后你的第二个请求可能会命中 worker2,它有自己的 python 执行环境,你的变量不可用,因为它们不是跨进程共享的。事实上,该变量中可能有一个值,但它属于不同的用户请求。

总之

  1. 它不保证同一对象在请求中可用
  2. 它可能会被同时使用您的应用的另一个用户覆盖

【讨论】:

  • 感谢 Shreyas。我使用 Nginx 作为反向代理运行 gunicorn 服务器。您介意详细说明为什么这不适用于生产服务器吗?
  • 有道理 Shreyas。谢谢...一个后续问题:我猜如果我使用flask-cache而不是将变量存储在current_app上,我可以克服这个问题。但是关于烧瓶缓存如何将正确的请求路由到正确的工作人员的任何线索?
  • 是的,如果你使用烧瓶缓存,你可以克服这个问题。但是您必须先腌制它,然后再将其存储在缓存中。或者我认为烧瓶会为你做到这一点。并且烧瓶缓存不会对工作人员进行任何路由。这仅适用于请求和工作人员
  • 看起来像烧瓶缓存泡菜,如果需要,它会自动取消泡菜。生病了,但我不愿接受这个作为答案,因为我仍在寻找适合我需要的解决方案。不知道如何在保持烧瓶应用无状态的同时做到这一点 - 我想这可能是不可能的,唯一的选择是在请求之间腌制和解开它......
  • 我也这么认为,这是不可能的。你可以尝试用泡菜实现吗?我认为延迟不会显着增加。使用更快的 cpickle。
【解决方案2】:

虽然我回答这个问题的时间很晚,但这仍然会对我们中的许多人有所帮助。 为了在请求之间共享值,您应该信任使用缓存内存。使用 flask-cache 和 redis 作为数据库,flask 中的缓存很容易实现。这将是最有效和最可靠的方式。阅读任何关于在flask中将redis实现为缓存数据库的文章以供进一步参考。

【讨论】:

  • Flask-Cache 的简单缓存策略不是线程安全的。您将需要以一种或另一种方式使用外部服务器。
猜你喜欢
  • 2020-07-01
  • 2015-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-19
  • 1970-01-01
  • 2015-05-24
  • 1970-01-01
相关资源
最近更新 更多