我有一个Flask应用程序,由Nginx和Gunicorn服务,有3名工作人员。我的Flask应用程序是一个API微服务器,专为执行NLP而设计,我正在使用spaCy库。
我的问题是他们占用了大量的RAM,因为加载spaCy管道spacy.load('en')
是非常耗费内存的,因为我有3个gunicorn工作者,每个需要大约400MB的RAM。
我的问题是,有没有办法加载管道一次并在我所有的gunicorn工作人员之间分享?
答案 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 中执行此操作:
和,
当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__)
之后发生。