【问题标题】:Python: ulimit and nice for subprocess.call / subprocess.Popen?Python:ulimit 和不错的 subprocess.call / subprocess.Popen?
【发布时间】:2010-12-13 22:54:43
【问题描述】:

我需要限制我使用 subprocess.call 从 python 进程生成的外部命令行应用程序占用的时间和 cpu,主要是因为有时生成的进程会卡住并将 cpu 固定在 99%。

nice 和 ulimit 似乎是执行此操作的合理方法,但我不确定它们如何与子进程交互。

  • 限制类似于:
    • 如果进程耗时超过 60 秒,则终止进程
    • 将其限制为 CPU 的 20%
  • 我想将资源限制应用于子进程,而不是生成子进程的 python 进程。

有没有办法将 nice 和 ulimit 应用于 subprocess.call 生成的进程?有更好的 Python 原生替代品吗?

这是在 linux (ubuntu) 系统上。

【问题讨论】:

  • 您可能希望接受投票最高的答案而不是我的答案。比我的好多了。

标签: python resources nice ulimit


【解决方案1】:

使用 preexec_fn 参数来 subprocess.Popen 和资源模块。示例:

parent.py:

#!/usr/bin/env python

import os
import sys
import resource
import subprocess

def setlimits():
    # Set maximum CPU time to 1 second in child process, after fork() but before exec()
    print "Setting resource limit in child (pid %d)" % os.getpid()
    resource.setrlimit(resource.RLIMIT_CPU, (1, 1))

print "CPU limit of parent (pid %d)" % os.getpid(), resource.getrlimit(resource.RLIMIT_CPU)
p = subprocess.Popen(["./child.py"], preexec_fn=setlimits)
print "CPU limit of parent (pid %d) after startup of child" % os.getpid(), resource.getrlimit(resource.RLIMIT_CPU)
p.wait()
print "CPU limit of parent (pid %d) after child finished executing" % os.getpid(), resource.getrlimit(resource.RLIMIT_CPU)

child.py:

#!/usr/bin/env python

import os
import sys
import resource

print "CPU limit of child (pid %d)" % os.getpid(), resource.getrlimit(resource.RLIMIT_CPU)

parent.py 将分叉到一个新进程中。在新进程中,它会调用 setlimits(),然后执行 child.py。这意味着资源将在子进程中受到限制,而不是在父进程中。

运行程序时的输出:

./parent.py
CPU limit of parent (pid 17404) (-1, -1)
Setting resource limit in child (pid 17405)
CPU limit of parent (pid 17404) after startup of child (-1, -1)
CPU limit of child (pid 17405) (1, 1)
CPU limit of parent (pid 17404) after child finished executing (-1, -1)

在许多情况下,这比尝试使用 ulimit 更好,因为通过 shell 生成子进程并不总是一个好主意,尤其是因为它经常导致丑陋的参数引用问题。

【讨论】:

  • 谢谢埃里克。看起来这是对 python 进程的限制,而不是对外部进程的限制?
  • 是的,资源包设置了python进程的限制(通过setrlimit)-但在我的例子中,它设置了subproces.Popen创建的子进程的限制,然后调用exec()运行孩子。因此,在示例中,调用进程的限制不受影响,只影响子进程的限制。
  • 这个答案100%正确,应该被选为正确答案。
  • 关于资源限制的好答案,但它没有解决nice的使用问题
  • os.nice 应添加到答案中。
【解决方案2】:

您可以使用ulimitnice shell 命令为子进程设置限制,如下所示:

import subprocess
subprocess.Popen('ulimit -t 60; nice -n 15 cpuhog', shell=True)

这运行cpuhog,CPU 时间限制为 60 秒,niceness 调整为 15。请注意,没有简单的方法来设置 20% 的 CPU 限制。该进程将使用 100% 的 CPU,除非另一个(不太好的)进程也需要 CPU。

【讨论】:

  • 感谢 Ville,您描述的 CPU 节流效果很好。你知道是否可以用括号语法而不是字符串来指定命令吗?
  • 据我所知,你必须在一个字符串中传递整个 shell 命令才能使这样的事情起作用。
  • 这确实不是应该标记为已接受答案的解决方案。结合用户提供的参数,这很容易最终打开一个安全漏洞。
【解决方案3】:

Erik 让我很轻松,但他忘记了 Rich 指出的nice 部分。我发现psutil 包很好(双关语),但不幸的是便携性较差。这是我对这个问题的看法:

import os
import psutil
import resource
import subprocess

def preexec_fn():
    pid = os.getpid()
    ps = psutil.Process(pid)
    ps.set_nice(10)
    resource.setrlimit(resource.RLIMIT_CPU, (1, 1))

print "mother pid", os.getpid()
p = subprocess.Popen(["./cpuhog.sh"], preexec_fn=preexec_fn)
p.wait()
print "mother still alive with pid", os.getpid()

Ville 使用了shell=True,我对此有些过敏。也许我只是老了,脾气暴躁,但我尽量避免!

【讨论】:

  • 当 Python 的内置 os 已经有 nice 时,为什么还需要 psutil
  • 可能是因为您不能将 PID 传递给 os.nice,但可以传递给 psutil
猜你喜欢
  • 2018-01-14
  • 2011-10-19
  • 2015-05-20
  • 1970-01-01
  • 1970-01-01
  • 2013-01-18
  • 1970-01-01
  • 2016-11-30
  • 1970-01-01
相关资源
最近更新 更多