Python: ulimit and nice for subprocess.call / subprocess.Popen?

45 人关注

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

nice和ulimit似乎是合理的方法,但我不确定它们如何与subprocess互动。

  • The limits look something like:
  • Kill the process if it's taking more than 60 seconds
  • Limit it to 20% of cpu
  • I want to apply the resource limiting to the subprocess, not to the python process that's spawning the subprocesses.
  • 有没有一种方法可以对subprocess.call产生的进程应用nice和ulimit?是否有更好的Python-native替代品?

    这是在一个linux(ubuntu)系统上。

    1 个评论
    你可能想接受得票最高的答案,而不是我的答案。 它比我的好得多。
    python
    resources
    nice
    ulimit
    Parand
    Parand
    发布于 2009-11-07
    3 个回答
    Erik Forsberg
    Erik Forsberg
    发布于 2014-04-06
    已采纳
    0 人赞同

    使用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催生子进程并不总是一个好主意,特别是它经常导致丑陋的参数引用麻烦。

    谢谢Erik。看起来这是对python进程的限制,而不是对外部进程的限制?
    是的,资源包设置了python进程的限制(通过setrlimit)--但在我的例子中,在调用exec()运行子进程之前,它设置了由subproces.Popen创建的子进程的限制。 所以,在这个例子中,调用进程的限制不受影响,只影响子进程的限制。
    这个答案是100%正确的,应该被选为正确答案。
    关于资源限制的好答案,但它没有涉及 nice 的使用。
    替换代码0】应被添加到答案中。
    Ville Laurikari
    Ville Laurikari
    发布于 2014-04-06
    0 人赞同

    你可以用 ulimit nice 这样的shell命令为子进程设置限制。

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

    这样运行cpuhog,CPU时间限制为60秒,漂亮度调整为15。 注意,没有简单的方法来设置20%的CPU节流。 该进程将使用100%的CPU,除非其他(不那么好的)进程也需要CPU。

    谢谢Ville,你描述的cpu节流效果很好。你知道是否有可能用括号语法而不是用字符串来指定命令,做同样的事情?
    据我所知,你必须在一个字符串中传递整个shell命令,这样的东西才能发挥作用。
    这确实不是应该被标记为接受答案的解决方案。与用户提供的参数相结合,这很容易最终打开一个安全漏洞。
    mogul
    mogul
    发布于 2014-04-06
    0 人赞同

    Erik 这对我来说很容易,但他忘记了 nice 的部分。 Rich 指出了这一点。我觉得 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)