9

我有一个内存密集型 Python 应用程序(几百 MB 到几 GB 之间)。
我有几个非常小的 Linux 可执行文件,主要应用程序需要运行,例如

child = Popen("make html", cwd = r'../../docs', stdout = PIPE, shell = True)
child.wait()

当我运行这些外部实用程序(一次,在长时间的主进程运行结束时)时,subprocess.Popen有时会得到OSError: [Errno 12] Cannot allocate memory.
我不明白为什么......请求的过程很小!
系统有足够的内存容纳更多的 shell。

我使用的是 Linux(Ubuntu 12.10,64 位),所以我猜子进程调用 Fork。
Fork 分叉了我现有的进程,从而使消耗的内存量增加了一倍,并且失败了??
“写时复制”发生了什么?

我可以在没有 fork 的情况下生成一个新进程(或者至少不复制内存 - 从新开始)?

有关的:

fork()、vfork()、exec()和clone()的区别

fork() & 内存分配行为

Python subprocess.Popen 出现 OSError 错误:[Errno 12] 一段时间后无法分配内存

使用 subprocess.Popen 的 Python 内存分配错误

4

1 回答 1

4

似乎不会出现真正的解决方案(即使用 vfork 的子进程的替代实现)。那么可爱的黑客怎么样?在你的进程开始时,生成一个内存占用很小的从属进程,准备好生成你的子进程,并在主进程的整个生命周期中保持与它的开放通信。

这是一个使用 rfoo ( http://code.google.com/p/rfoo/ ) 和一个名为 rfoosocket 的命名 unix 套接字的示例(您显然可以使用 rfoo 支持的其他连接类型,或其他 RPC 库):

服务器:

import rfoo
import subprocess

class MyHandler(rfoo.BaseHandler):
    def RPopen(self, cmd):
        c = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
        c.wait()
        return c.stdout.read()

rfoo.UnixServer(MyHandler).start('rfoosocket')

客户:

import rfoo

# Waste a bunch of memory before spawning the child. Swap out the RPC below
# for a straight popen to show it otherwise fails. Tweak to suit your
# available system memory.
mem = [x for x in range(100000000)]

c = rfoo.UnixConnection().connect('rfoosocket')

print rfoo.Proxy(c).RPopen('ls -l')

如果您需要与生成的子进程进行实时的来回协同进程交互,此模型可能不起作用,但您可能能够破解它。您可能想要清理可以传递给 Popen 的可用参数根据您的特定需求,但这都应该相对简单。

您还应该发现在客户端启动时启动服务器并管理要在退出时清理的套接字文件(或端口)很简单。

于 2013-07-04T00:43:46.327 回答