私は次を使用してサブプロセスを実行します:
p = subprocess.Popen("subprocess",
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE)
このサブプロセスは、stderrでエラーが発生してすぐに終了するか、実行を続けます。私はこれらの状態のいずれかを検出したい-後者は数秒待つことによって。
私はこれを試しました:
SECONDS_TO_WAIT = 10
select.select([],
[p.stdout, p.stderr],
[p.stdout, p.stderr],
SECONDS_TO_WAIT)
しかし、それだけを返します:
([],[],[])
どちらの条件でも。私に何ができる?
Popen.Poll()メソッドを使用してみましたか?あなたはこれを行うことができます:
p = subprocess.Popen("subprocess",
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE)
time.sleep(SECONDS_TO_WAIT)
retcode = p.poll()
if retcode is not None:
# process has terminated
これにより、常に10秒待つことになりますが、失敗のケースがまれである場合、これはすべての成功のケースで償却されます。
編集:
どうですか:
t_nought = time.time()
seconds_passed = 0
while(p.poll() is not None and seconds_passed < 10):
seconds_passed = time.time() - t_nought
if seconds_passed >= 10:
#TIMED OUT
これは忙しい待機の醜さを持っていますが、私はそれがあなたが望むものを達成すると思います。
さらに、select callのドキュメントをもう一度見て、次のように変更することをお勧めします。
SECONDS_TO_WAIT = 10
select.select([p.stderr],
[],
[p.stdout, p.stderr],
SECONDS_TO_WAIT)
通常はstderrから読み取る必要があるため、読み取り可能なものがいつあるか(つまり、失敗の場合)を知りたいとします。
これがお役に立てば幸いです。
これは私が思いついたものです。必要なときに機能し、pプロセスでタイムアウトする必要はありませんが、セミビジーループを使用します。
def runCmd(cmd, timeout=None):
'''
Will execute a command, read the output and return it back.
@param cmd: command to execute
@param timeout: process timeout in seconds
@return: a Tuple of three: first stdout, then stderr, then exit code
@raise OSError: on missing command or if a timeout was reached
'''
ph_out = None # process output
ph_err = None # stderr
ph_ret = None # return code
p = subprocess.Popen(cmd, Shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
# if timeout is not set wait for process to complete
if not timeout:
ph_ret = p.wait()
else:
fin_time = time.time() + timeout
while p.poll() == None and fin_time > time.time():
time.sleep(1)
# if timeout reached, raise an exception
if fin_time < time.time():
# starting 2.6 subprocess has a kill() method which is preferable
# p.kill()
os.kill(p.pid, signal.SIGKILL)
raise OSError("Process timeout has been reached")
ph_ret = p.returncode
ph_out, ph_err = p.communicate()
return (ph_out, ph_err, ph_ret)
ここに素敵な例があります:
from threading import Timer
from subprocess import Popen, PIPE
def kill_proc():
proc.kill()
proc = Popen("ping 127.0.0.1", Shell=True)
t = Timer(60, kill_proc)
t.start()
proc.wait()
上記のコメントで述べたように、毎回出力を微調整してコマンドを再実行するだけの場合、次のような作業を行いますか?
from threading import Timer
import subprocess
WAIT_TIME = 10.0
def check_cmd(cmd):
p = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
def _check():
if p.poll()!=0:
print cmd+" did not quit within the given time period."
# check whether the given process has exited WAIT_TIME
# seconds from now
Timer(WAIT_TIME, _check).start()
check_cmd('echo')
check_cmd('python')
上記のコードを実行すると、以下が出力されます。
python did not quit within the given time period.
上記のコードで考えられる唯一の欠点は、check_cmdを実行し続けるときに重複する可能性があるプロセスです。
import subprocess as sp
try:
sp.check_call(["/subprocess"], timeout=10,
stdin=sp.DEVNULL, stdout=sp.DEVNULL, stderr=sp.DEVNULL)
except sp.TimeoutError:
# timeout (the subprocess is killed at this point)
except sp.CalledProcessError:
# subprocess failed before timeout
else:
# subprocess ended successfully before timeout
TimeoutExpired docs を参照してください。
これはエヴァンの答えの言い換えですが、以下を考慮しています:
タイマーアプローチには固有の競合があります(タイマーがプロセスを強制終了しようとすると、直後プロセスが終了し、これがWindowsでは例外が発生します)。
DEVNULL = open(os.devnull, "wb")
process = Popen("c:/myExe.exe", stdout=DEVNULL) # no need for stdout
def kill_process():
""" Kill process helper"""
try:
process.kill()
except OSError:
pass # Swallow the error
timer = Timer(timeout_in_sec, kill_process)
timer.start()
process.wait()
timer.cancel()