web-dev-qa-db-ja.com

Python:subprocess.call / subprocess.PopenのulimitとNice?

pythonプロセスをsubprocess.callを使用して作成した外部コマンドラインアプリが使用する時間とCPUの量を制限する必要があります。主に、作成されたプロセスがスタックし、CPUを99にピン留めするためです。 %。

Niceとulimitはこれを行うための合理的な方法のように見えますが、サブプロセスとどのように相互作用するかはわかりません。

  • 制限は次のようになります。
    • 60秒以上かかる場合はプロセスを強制終了します
    • CPUの20%に制限する
  • リソース制限をサブプロセスに適用したいのですが、サブプロセスを生成しているpythonプロセスには適用しません。

Niceとulimitをsubprocess.call生成されたプロセスに適用する方法はありますか? Pythonネイティブの代替案はありますか?

これはLinux(ubuntu)システム上にあります。

40
Parand

次のようなulimitおよびNiceシェルコマンドを使用して、サブプロセスの制限を設定できます。

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

これはcpuhogを実行し、制限は60秒のCPU時間と15のナイスネス調整です。20%のCPUスロットルをそのように設定する簡単な方法はないことに注意してください。別の(Niceが少ない)プロセスもCPUを必要としない限り、プロセスは100%CPUを使用します。

12
Ville Laurikari

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()を呼び出してから、exec 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を使用するよりも優れたソリューションです。シェルを介してサブプロセスを生成することは常に良い考えとは限らないためです。

107
Erik Forsberg

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

VilleShell=Trueなんとなくアレルギーです。たぶん私はここで年老いて不機嫌ですが、それを避けようとしています!

9
mogul