python subprocess poll()不会返回None,即使Popen仍在运行
我有一个python脚本,它使用while循环和sleep(如下所示)执行带超时的linux命令python subprocess poll()不会返回None,即使Popen仍在运行,python,timeout,subprocess,pipe,python-2.4,Python,Timeout,Subprocess,Pipe,Python 2.4,我有一个python脚本,它使用while循环和sleep(如下所示)执行带超时的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.P
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秒,cat仍会继续,直到完成。我是不是遗漏了什么?请帮助。除了我在代码中看到的问题之外
- 使用
和stdin=subprocess.PIPE
调用stderr=subprocess.PIPE
Popen()。但你从来不会处理这些管道。使用类似于
的命令,这应该没问题,但可能会导致问题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列的缩进深度。它在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
它还可以使用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()
在Linux上不测量子时间time.clock()
- 我们不能在纯Python中模仿Python 3.3中的
由于time.monotonic()
ctypes在Python 2.4上不可用
- 允许在休眠状态下生存,例如,如果超时时间为5秒,则在休眠前2秒+计算机唤醒后3秒
#/usr/bin/env python2.4
导入操作系统
输入信号
导入系统
导入临时文件
导入时间
从子流程导入Popen
类TimeoutExpired(异常):
通过
def wait(进程、超时、睡眠时间=.1):
对于x范围内的u(int(超时*1./_睡眠时间+.5)):
时间。睡眠(_sleep_time)#注意:假设它醒得不早
如果process.poll()不是无:
返回进程。等待()
raise TimeoutExpired#注意:超时精度不是很高
f=tempfile.TemporaryFile()
p=Popen([“/bin/bash”,“-c”,sys.argv[1]],stdout=f,preexec_fn=os.setsid,
关闭(fds=真)
尝试:
等待(p,超时=5)
除TimeoutExpired外:
打印>>sys.stderr,“超时”
os.killpg(os.getpgid(p.pid),signal.SIGKILL)
p、 等等
其他:
f、 搜索(0)
对于f中的行:
打印行,
f、 close()#删除它
打印>>sys.stderr,“完成”
我使用Python2.4.3在RHEL5.5上运行,我认为有可能cat
将所有数据都放在输出流中,但您的终端速度太慢,无法读取所有数据。如果您尝试像:while:;做回声“嗨”;睡眠1;完成
?您能详细说明一下您看到的内容吗?粘贴的输出看起来像是首次运行循环后退出的while循环。它似乎不应该进入超时代码。$time my_script-c”while:;do echo“hi”;sleep 1;done“2>&1-t5选项。超时=5经过=1经过=2经过=3经过=4经过=5实际的0m5.155s用户0m0.039s系统0m0.012s
看起来在“hi”时超时情况下工作正常。你能详细说明一下在我的例子中发生了什么吗?在我的例子中,我做了一个100MB的文件,其中填充了/dev/zero@KurtStutsman我正在尝试cat一个100MB的文件,其中填充了/dev/zero。]<代码>$time cat file2 real 0m10.481s用户0m0.004s系统0m0.734s我深表歉意<代码>轮询()即使进程仍在运行,也不会返回None。这可能是一个新手问题,但如何以不同的方式处理stdin和stderr管道?如果您能给我指出如何处理管道的相关链接,这将有所帮助。我以前使用过带超时的pexpect,但遇到了一些问题,因为pexpect超时对系统时间变化很敏感。所以我求助于使用上面的python代码。我上面的问题是,如果子进程“cat”需要11秒来处理,为什么poll()函数只运行一次?我在脚本中检查了缩进。这不是问题所在。我仍然看到我的子进程在上面的while循环中运行了11秒。我试过这样的脚本$ls-alrt file2
-rw-r--r--1根根根104857600 10月19日14:56 file2$time cat file2
real 0m10.468s用户0m0.011s sys 0m0.710s$time脚本“cat file2”
done real 0m11.360s用户0m0.152s sys 0m1.278smy文件2是通过此dd命令创建的dd if=/dev/zero of=./file2 bs=100M count=1
感谢您的回复。你的脚本在5秒内没有超时。让我知道填充了/dev/zero的文件的cat是否与其他文件的行为不同,或者我是否丢失了something@yalkris:没有超时,因为cat
在5秒之前完成。剩下的时间是在中为f
循环中的行打印零字节(一次迭代,因为文件中没有换行符),在我的终端上没有可见的输出(尝试cat-v file2
查看零字节)。如果将脚本重定向到devnull,它应该在不到一秒的时间内结束:超时时间“cat file2”>/dev/null
。如果愿意,可以限制整个脚本的执行时间(例如,只需调用自身)