2012-10-19 28 views
0

我有使用while循環和睡眠像下面蟒子輪詢()沒有返回無即使POPEN仍在運行

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 

我的問題是在這上面超時執行的Linux命令的python腳本即使超時時間爲5秒,貓也會一直持續到完成。我在這裏錯過了什麼嗎?請幫忙。

+0

我與Python 2.4.3 – yalkris

+1

上RHEL5.5運行,我認爲有可能是'cat'把所有的數據輸出流中,但你的終端是讀它太慢所有。如果你嘗試像下面這樣的命令會發生什麼:'while:;做回聲「嗨」;睡1;完成'? – mgilson

+0

你能詳細介紹一下你看到的內容嗎?你粘貼的輸出看起來像循環第一次運行後退出的while循環。它似乎沒有進入超時代碼。 –

回答

1

它將按預期在Ubuntu:

$ /usr/bin/ssh [email protected] -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 [email protected] -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 

它也可以用shell命令工作:

$ /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 由於​​在Python 3.3模擬time.monotonic()不可用Python的2.4

  • 是可以接受的生存冬眠例如,在休眠之前2秒+在計算機被喚醒後3秒,如果超時爲5秒,則每當它發生時喚醒。

#!/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" 
+0

我想你這樣的腳本'$ LS -alrt file2' -RW-R - R-- 1個根根104857600 10月19日14:56文件2 '$時間貓file2' 真正0m10.468s 用戶0m0 .011s SYS 0m0.710s '$時間your_script 「貓文件2」' 做 真正0m11.360s 用戶0m0.152s SYS 0m1.278s – yalkris

+0

我的文件2是由該DD命令創建'DD如果=/dev/zero =。/ file2 bs = 100M count = 1' – yalkris

+0

感謝您的回覆。你的腳本在5秒內沒有超時。讓我知道如果一個文件的貓充滿/ dev /零的行爲與其他文件的行爲不同,或者我缺少一些東西 – yalkris

0

除了在你的代碼

  • 我看到的問題你叫Popen()stdin=subprocess.PIPEstderr=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列的縮進深度。

+0

我對此表示歉意。即使進程仍在運行,poll()也不會返回None。可能是一個新手問題,但如何以不同的方式處理stdin和stderr管道?如果您能指點我相關的關於如何處理管道的鏈接,這將有所幫助。我之前使用超時過期的pexpect,但遇到問題,因爲pexpect超時對系統時間更改很敏感。所以我使用了上面的Python代碼。我上面的問題是,如果子進程「貓」需要11秒來處理爲什麼我的poll()函數只運行一次? – yalkris

+0

我在腳本中檢查了縮進。這不是問題。我仍然看到我的子進程在while循環中運行了11秒。 – yalkris

相關問題