【问题标题】:subprocess.check_output without high memory usagesubprocess.check_output 没有高内存使用
【发布时间】:2015-08-31 02:04:28
【问题描述】:

在我当前的项目中,我有一个网络服务器,它调用 Linux 命令来获取然后显示在网站上的信息。我遇到的问题是网络服务器运行在只有 256 MB RAM 的微型嵌入式设备(它基本上是设备的配置工具)上。网络服务器本身确实占用了我该设备上一半以上的可用 RAM。

现在,当我尝试使用 subprocess.check_output() 调用命令时,fork 很快就会使 RAM 使用量翻倍(据我所知,因为它克隆了父进程或其他东西),从而使整个事情崩溃了一个“ Out of Memory”,虽然被调用的进程很小。

由于该设备使用相当便宜的闪存芯片,如果过度使用这些芯片会失效,我不想使用任何交换解决方案或其他基于增加虚拟内存的解决方案。

到目前为止,我尝试做的是在程序开始时打开一个 sh 会话,当它的内存使用率仍然很低时,然后将命令写入该 sh 会话并读取输出。这有点工作,但它很不稳定,因为错误的“退出”或类似的东西可能会使整个事情崩溃。

有没有类似于 subprocess.check_output() 的解决方案不会使我的内存使用量翻倍?

【问题讨论】:

  • 顺便说一句,您使用的是什么网络服务器?
  • 这是一个使用 web.py 作为框架的自编程。
  • 想把它贴在某个地方让我们看看吗?
  • 对; 足够公平。我可以想到两种方法来解决这个问题。 1) 减少您的网络服务器/应用程序的内存占用 2) 运行另一个独立于您的网络服务器/应用程序的守护程序,该守护程序可以通过 UNIX 套接字/管道进行通信。
  • 问题是由于os.fork() 而标准解决方案是一个fork-server(一个产生其他进程的专用进程--基于multiprocessing而不是sh-基于你的题)。相关:Python subprocess.Popen “OSError: [Errno 12] Cannot allocate memory”

标签: python linux memory subprocess


【解决方案1】:

所以在 J.F. Sebastian 的帮助下,我想通了。

这是我最后使用的代码:

from multiprocessing import Process, Queue
from subprocess import check_output, CalledProcessError

def cmdloop(inQueue,outQueue):
    while True:
        command = inQueue.get()
        try:
            result = check_output(command,shell=True)
        except CalledProcessError as e:
            result = e

        outQueue.put(result)

inQueue = Queue()
outQueue = Queue()
cmdHostProcess = Process(target=cmdloop, args=(inQueue,outQueue,))
cmdHostProcess.start()

def callCommand(command):
    inQueue.put(command)
    return outQueue.get()

def killCmdHostProcess():
    cmdHostProcess.terminate()

在 Python 3.4+ 中,我可以使用 multiprocessing.set_start_method('forkserver'),但由于它在 Python 2.7 上运行,因此很遗憾不可用。

这仍然大大减少了我的内存使用量,并以干净的方式解决了问题。非常感谢您的帮助!

【讨论】:

  • 这是一个很好的解决问题的方法,但是 Python 一开始就必须这样做的事实很糟糕。
  • 不错的解决方案!值得指出的是,您不应该轻易使用shell=True,正如docs.python.org/2/library/… 的文档中也提到的那样,它也许对RAM 的使用也有负面影响(也许是两个叉而不是一个?)。你也可能想赶上OSErrors。
  • 你有任何证据证明这个额外的副本有很大的开销吗? AFAIK 写时复制应该避免这种开销。
  • 好吧,如果我按照常规方式进行操作,os.fork() 会失败并出现内存不足错误(即使在执行像 echo 这样的小型可执行文件时),如果我按照现在的方式进行操作,即使在执行较大的可执行文件时也完全没有问题。
  • 很好的解决方案!当“命令”引发异常时,我遇到了一个问题,导致这个神秘的错误消息:“TypeError:('__init__()至少需要3个参数(1个给定)',,()) ”。这是由于 Python 无法正确腌制“result = e”行中的异常对象,导致“outQueue.get()”抛出上述错误。解决方案是使用bugs.python.org/issue9400#msg274638 中的解决方法,因为该错误修复未向后移植到 Python 2.7
猜你喜欢
  • 1970-01-01
  • 2017-07-03
  • 2013-07-11
  • 1970-01-01
  • 2014-05-02
  • 2011-11-06
  • 2016-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多