我在这两个问题中使用了代码
如何从 Python 中的线程获取返回值
具有超时的子进程
并得到了这个
import subprocess, threading, os
class ThreadWithReturnValue(threading.Thread):
def __init__(self, group=None, target=None, name=None, args=(), kwargs={}, Verbose=None):
threading.Thread.__init__(self, group, target, name, args, kwargs, Verbose)
self._return = None
def run(self):
if self._Thread__target is not None:
self._return = self._Thread__target(*self._Thread__args, **self._Thread__kwargs)
def join(self, timeout = None):
threading.Thread.join(self, timeout)
return self._return
class SubprocessWrapper(object):
def __init__(self, cmd, timeout):
self.cmd = cmd
self.process = None
self.timeout = timeout
def run(self):
def target(cmd):
self.process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr = subprocess.PIPE)
returnValue = self.process.communicate()
return [returnValue[0], returnValue[1], self.process.returncode]
thread = ThreadWithReturnValue(target=target, args=[self.cmd])
thread.start()
returnValue = thread.join(self.timeout)
if thread.is_alive():
print 'cmd = ',self.cmd
self.process.kill()
returnValue = thread.join()
print 'rc = ', returnValue[2]
output = returnValue[0]
error = returnValue[1]
rc = returnValue[2]
return (output, rc)
os.system('date +%T.%N')
s1 = SubprocessWrapper("echo 'Process started'; sleep 2; echo 'Process finished'", timeout = 3)
s1.run()
os.system('date +%T.%N')
s2 = SubprocessWrapper("echo 'Process started'; sleep 2; echo 'Process finished'", timeout = 1)
s2.run()
os.system('date +%T.%N')
问题是输出是
11:20:34.963947950
11:20:36.986685289
cmd = echo 'Process started'; sleep 2; echo 'Process finished'
rc = -9
11:20:38.995597397
因此,您可以看到应该在一秒钟后终止的进程实际上花了 2 秒。发生这种情况是因为join()
但在问题中subprocess with timeout
这工作正常。这意味着当我集成两个代码时,我导致了这个问题,我的问题是如何解决它?我在想我可能需要以不同的方式调用threading.Thread.__init__
方法,但我不明白如何。
尽管超时,此代码在一秒钟内不会返回输出。它在睡眠后两秒内返回:
#!/usr/bin/env python3
from subprocess import TimeoutExpired, check_output as qx
from timeit import default_timer as timer
start = timer()
try:
qx("echo 'Process started'; sleep 2; echo 'Process finished'",
shell=True, universal_newlines=True, timeout=1)
except TimeoutExpired as e:
print("Got %r in %.2f seconds" % (e.output, timer() - start))
else:
assert 0 # should not get here
输出
在 2.00 秒内获得"进程启动"
来自"停止读取 Python 中的进程输出而不挂起?"问题的基于警报的解决方案有效:
#!/usr/bin/env python
import signal
from subprocess import Popen, PIPE
from timeit import default_timer as timer
class Alarm(Exception):
pass
def alarm_handler(signum, frame):
raise Alarm
start = timer()
# start process
process = Popen("echo 'Process started'; sleep 2; echo 'Process finished'",
shell=True, stdout=PIPE, bufsize=1, universal_newlines=True)
# set signal handler
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(1) # produce SIGALRM in a second
buf = []
try:
for line in iter(process.stdout.readline, ""):
buf.append(line) # assume it is atomic
except Alarm:
process.kill()
else:
signal.alarm(0) # reset alarm
finally:
output = ''.join(buf)
print("Got %r in %.2f seconds" % (output, timer() - start))
process.stdout.close()
process.wait()
输出
在 1.00 秒内获得"进程启动"