44

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

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

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

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

这是在 linux (ubuntu) 系统上。

4

3 回答 3

116

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

父.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)

孩子.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 生成子进程并不总是一个好主意,尤其是因为它经常导致丑陋的参数引用问题。

于 2009-11-06T19:59:22.150 回答
11

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

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

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

于 2009-11-06T19:28:06.893 回答
11

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()

维尔使用了shell=True我对它过敏的东西。也许我在这里只是又老又脾气暴躁,但我尽量避免它!

于 2014-04-06T08:12:15.310 回答