在我的gunicorn工作人员之间共享数据

时间:2017-04-18 08:29:57

标签: python gunicorn spacy

我有一个Flask应用程序,由Nginx和Gunicorn服务,有3名工作人员。我的Flask应用程序是一个API微服务器,专为执行NLP而设计,我正在使用spaCy库。

我的问题是他们占用了大量的RAM,因为加载spaCy管道spacy.load('en')是非常耗费内存的,因为我有3个gunicorn工作者,每个需要大约400MB的RAM。

我的问题是,有没有办法加载管道一次并在我所有的gunicorn工作人员之间分享?

4 个答案:

答案 0 :(得分:1)

我需要在实例之间共享千兆字节的数据并使用内存映射文件 (https://docs.python.org/3/library/mmap.html)。如果您需要从池中检索每个请求的数据量很小,这可以正常工作。否则,您可以挂载一个 ramdisk,您可以在其中找到挂载的文件。

由于我不熟悉 SpaCy,我不确定这是否有帮助。我会让一名工人在加载 (spacy.load?) 时实际处理数据并将生成的文档 (pickling/marshalling) 写入其他工人可以从中读取的 mmf。

要更好地了解 mmap,请查看 https://realpython.com/python-mmap/

答案 1 :(得分:0)

一种解决方法是,您可以预先加载 spaCy 管道、pickle(或任何舒适的序列化方式)结果对象并将其存储在数据库或文件系统中。每个工作人员都可以获取序列化的对象,然后简单地反序列化它。

答案 2 :(得分:0)

在 worker 之间共享内存管道可能对您有所帮助。

请检查gc.freeze

我认为,只需在您的 app.py 中执行此操作:

  1. 冻结 gc
  2. 加载管道或任何其他将使用大量内存的资源
  3. 解冻 gc

和,

  • 确保您的工作人员不会修改(直接或间接)冻结期间创建的任何对象
  • 将 app.py 传递给 gunicorn

fork发生时,那些持有大量资源的内存页不会被操作系统真正复制,因为你确保没有对其进行写操作。

如果不冻结gc,内存页仍然会被写入,因为gc正在写入对象引用计数。这就是为什么冻结很重要。

我只知道这种方式,但我没有尝试过。

答案 3 :(得分:0)

This 是一个在 2021 年使用 Python3.6 和 3.9(都经过测试)的答案。我和你有同样的设置,使用 Flask 部署一个 Spacy NLU API。解决方案是简单地将 --preload 附加到 gunicorn 命令,如下所示: gunicorn src.main:myFlaskApp --preload。这将导致 fork 在整个 src/main.py 文件执行后发生,而不是在 myFlaskApp = Flask(__name__) 之后发生。