防止在uWSGI worker中多次加载大对象?

时间:2015-09-10 22:32:30

标签: python uwsgi

我有一个非常大的自定义数据结构(类似于trie,虽然这对问题并不重要)我正在使用它来访问和提供数据。我正在将我的应用程序移动到uWSGI以供生产使用,我绝对不希望每个工人重新加载。我可以以某种方式在工作进程之间共享它吗?我只需加载一次结构,然后通过apscheduler每分钟重新加载一次。没有任何工作人员以任何方式修改数据结构。还有另一种更好的解决方案可以解决这类问题吗?每个工人加载相同的东西是非常浪费的。

1 个答案:

答案 0 :(得分:0)

根据数据结构的类型,您可以尝试使用内存映射文件。有一个Python library包含相关的系统调用。

文件的结构需要反映您正在使用的数据结构。例如,如果您需要trie,则可以将所有字符串存储在已排序的列表中,并对前缀进行二进制搜索,以查看哪些字符串具有该前缀。

当您访问文件中的页面时,它们将通过操作系统的磁盘读取缓存加载到内存中。对同一页面的后续请求将很快。由于磁盘缓存可以在进程之间共享,因此所有UWSGI工作人员都将从访问缓存页面的速度中受益。

我在Linux上试图通过强制它在两个独立的进程中扫描一个大文件来尝试这个。创建一个名为' big'的大文件,然后在两个单独的Python进程中运行以下命令:

import mmap
with open('big') as fp:
    map = mmap.mmap(fp.fileno(), 0, mmap.MAP_PRIVATE)
    if x == 'a':  # Make sure 'a' doesn't occur in the file!
        break

您会注意到两个进程的驻留内存在扫描文件时会增长,但共享内存使用情况也会增加。例如,如果big是1 GB文件,则两个进程似乎都使用大约1 GB的内存。但是,系统上的总内存负载将仅增加1 gb,而不是2 gb。

显然,这种方法存在一些限制,主要是您希望共享的数据结构很容易以二进制格式表示。此外,Python需要在您访问它们时将文件中的任何字节复制到内存中。如果您经常以小块读取整个文件,这会导致积极的垃圾收集,或者如果您阅读大块文件,则会破坏内存映射的共享内存优势。