[英]python subprocess poll() is not returning None even if Popen is still running
I have a python script that executes linux commands with timeout using a while loop and sleep like below 我有一个使用while循环和睡眠的python脚本,它执行超时的linux命令,如下所示
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
My question is in that above case even if the timeout is 5 seconds cat continues till it finishes. 我的问题是在上述情况下,即使超时为5秒,猫仍会继续操作直至完成。 Am I missing something here? 我在这里想念什么吗? Please help. 请帮忙。
It works as expected on Ubuntu: 它可以在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
It also work with a shell command: 它也可以使用shell命令:
$ /usr/bin/time python2.4 myscript.py 'while : ; do sleep 1; done'
timeout
done
0.02user 0.00system 0:05.03elapsed 0%CPU
Assumptions: 假设:
you can't use time.time()
due to possibility of a system clock change 您可能无法使用time.time()
因为可能会更改系统时钟
time.clock()
doesn't measure children times on Linux time.clock()
在Linux上不测量子时间
we can't emulate time.monotonic()
from Python 3.3 in pure Python due to ctypes
is not available on Python 2.4 由于ctypes
无法在纯Python中从Python 3.3模拟time.monotonic()
,因此在Python 2.4上不可用
it is acceptable to survive hibernation eg, 2 seconds before hibernation + 3 seconds after computer wakes up whenever it happens if timeout is 5 seconds. 如果超时为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"
Beside of the problems I see in your code 除了我在您的代码中看到的问题之外
Popen()
with stdin=subprocess.PIPE
and stderr=subprocess.PIPE
. 您可以使用stdin=subprocess.PIPE
和stderr=subprocess.PIPE
Popen()
调用Popen()
。 But you never handle these pipes. 但是您永远不会处理这些管道。 With a command like cat file2
, this should be fine, but it can lead to problems. 使用cat file2
类的命令,应该可以,但是会导致问题。 I can spot a potential misbehaviour: you might have mixed up indentation (as in the 1st version of your question). 我可以发现一个潜在的错误行为:您可能已经将缩进混淆了(如问题的第1版)。 Assume you have the following: 假设您具有以下条件:
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
You don't reach the timeout threshold, and nevertheless p.wait()
is called due to a bad indentation. 您没有达到超时阈值,但是由于缩进错误而调用了p.wait()
。 Don't mix up tabs and spaces; 不要混淆制表符和空格; PEP 8 suggests to use spaces only and a indentation depth of 4 columns. PEP 8建议仅使用空格,压痕深度为4列。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.