0

私は、whileループを使用してタイムアウトでLinuxコマンドを実行し、以下のようにスリープするPythonスクリプトを持っています

fout = tempfile.TemporaryFile()
try:
    p = subprocess.Popen(["/bin/bash","-c", options.command], bufsize=-1, shell=False, preexec_fn=os.setsid, stdin=subprocess.PIPE, stdout=fout, stderr=subprocess.PIPE)
except:
    sys.exit(UNEXPECTED_ERROR)
if options.timeout:
    print "options.timeout = %s" % options.timeout
    elapsed = 0
    time.sleep(0.1) # This sleep is for the delay between Popen and poll() functions
    while p.poll() is None:
        time.sleep(1)
        elapsed = elapsed + 1
        print "elapsed = %s" % elapsed
        if elapsed >= options.timeout:
            # TIMEDOUT
            # kill all processes that are in the same child process group
            # which kills the process tree
            pgid = os.getpgid(p.pid)    
            os.killpg(pgid, signal.SIGKILL)
            p.wait()
            fout.close()
            sys.exit(TIMEOUT_ERROR)
            break
else:
    p.wait()

fout.seek(0) #rewind to the beginning of the file
print fout.read(),
fout.close()
sys.exit(p.returncode)

$ time myScript -c "cat file2" 2>&1 -t 5
options.timeout = 5
elapsed = 1

real    0m11.811s
user    0m0.046s
sys     0m1.153s

私の質問は、上記の場合、タイムアウトが5秒であっても、猫は終了するまで続きます。ここで何かが足りませんか?助けてください。

4

2 に答える 2

1

Ubuntuでは期待どおりに機能します。

$ /usr/bin/ssh root@localhost -t 'sync && echo 3 > /proc/sys/vm/drop_caches'
$ /usr/bin/time python2.4 myscript.py 'cat big_file'
timeout
done
0.01user 0.63system 0:05.16elapsed 12%CPU 

$ /usr/bin/ssh root@localhost -t 'sync && echo 3 > /proc/sys/vm/drop_caches'
$ /usr/bin/time cat big_file >/dev/null
0.02user 0.82system 0:09.93elapsed 8%CPU

また、シェルコマンドでも機能します。

$ /usr/bin/time python2.4 myscript.py 'while : ; do sleep 1; done'
timeout
done
0.02user 0.00system 0:05.03elapsed 0%CPU

仮定:

  • time.time()システム時計が変わる可能性があるため使用できません

  • time.clock()Linuxでは子供の時間を測定しません

  • Python 2.4では利用できないtime.monotonic()ため、純粋なPythonでPython3.3からエミュレートすることはできません。ctypes

  • 休止状態を生き残ることは許容されます。たとえば、タイムアウトが5秒の場合は、休止状態の2秒前+コンピューターがウェイクアップしてから3秒後に発生します。

#!/usr/bin/env python2.4
import os
import signal
import sys
import tempfile
import time
from subprocess import Popen

class TimeoutExpired(Exception):
    pass

def wait(process, timeout, _sleep_time=.1):
    for _ in xrange(int(timeout * 1. / _sleep_time + .5)):
        time.sleep(_sleep_time)  # NOTE: assume it doesn't wake up earlier
        if process.poll() is not None:
            return process.wait()
    raise TimeoutExpired  # NOTE: timeout precision is not very good

f = tempfile.TemporaryFile() 
p = Popen(["/bin/bash", "-c", sys.argv[1]], stdout=f, preexec_fn=os.setsid,
          close_fds=True)
try:
    wait(p, timeout=5)
except TimeoutExpired:
    print >>sys.stderr, "timeout"
    os.killpg(os.getpgid(p.pid), signal.SIGKILL)
    p.wait()
else:
    f.seek(0)
    for line in f:
        print line,
f.close()  # delete it
print >>sys.stderr, "done"
于 2012-10-21T22:37:59.650 に答える
0

私があなたのコードで見る問題のほかに

  • Popen()とでstdin=subprocess.PIPE呼び出しますstderr=subprocess.PIPE。しかし、これらのパイプを処理することはありません。のようなコマンドを使用するとcat file2、これは問題ないはずですが、問題が発生する可能性があります。

私は潜在的な不正行為を見つけることができます:あなたはインデントを混同しているかもしれません(あなたの質問の最初のバージョンのように)。次のものがあると仮定します。

while p.poll() is None:
    time.sleep(1)
    elapsed = elapsed + 1
    print "elapsed = %s" % elapsed
    if elapsed >= options.timeout:
        # TIMEDOUT
        # kill all processes that are in the same child process group
        # which kills the process tree
        pgid = os.getpgid(p.pid)    
        os.killpg(pgid, signal.SIGKILL)
    p.wait()
    fout.close()
    sys.exit(TIMEOUT_ERROR)
    break

タイムアウトのしきい値に達していませんが、p.wait()インデントが正しくないために呼び出されます。タブとスペースを混同しないでください。PEP 8は、スペースのみと4列のインデントの深さを使用することを提案しています。

于 2012-10-19T20:23:54.833 に答える