Вы попытались использовать Popen. Опрос () метод. Вы могли просто сделать это:
p = subprocess.Popen("subprocess",
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE)
time.sleep(SECONDS_TO_WAIT)
retcode = p.poll()
if retcode is not None:
# process has terminated
Это заставит Вас всегда ожидать 10 секунд, но если бы случай возникновения отказов редок, это было бы амортизировано по всем случаям успеха.
<час>Редактирование:
Как насчет:
t_nought = time.time()
seconds_passed = 0
while(p.poll() is not None and seconds_passed < 10):
seconds_passed = time.time() - t_nought
if seconds_passed >= 10:
#TIMED OUT
Это имеет уродство того, чтобы быть активным ожиданием, но я думаю, что оно выполняет то, что Вы хотите.
Дополнительно рассмотрение избранной документации вызова снова я думаю, что можно хотеть изменить его следующим образом:
SECONDS_TO_WAIT = 10
select.select([p.stderr],
[],
[p.stdout, p.stderr],
SECONDS_TO_WAIT)
, Так как Вы обычно хотели бы читать из stderr, Вы хотите знать, когда он имеет что-то в наличии для чтения (т.е. случай возникновения отказов).
я надеюсь, что это помогает.
Используя выбор и сон действительно не имеет большого количества смысла. выбор (или любой механизм опроса ядра) по сути полезен для асинхронного программирования, но Ваш пример синхронен. Так или перепишите свой код, чтобы использовать нормальный вид блокирования или рассмотреть использование Скрученный:
from twisted.internet.utils import getProcessOutputAndValue
from twisted.internet import reactor
def stop(r):
reactor.stop()
def eb(reason):
reason.printTraceback()
def cb(result):
stdout, stderr, exitcode = result
# do something
getProcessOutputAndValue('/bin/someproc', []
).addCallback(cb).addErrback(eb).addBoth(stop)
reactor.run()
Кстати, существует более безопасный способ сделать это со Скрученным путем записи собственного ProcessProtocol:
http://twistedmatrix.com/projects/core/documentation/howto/process.html
Если, поскольку Вы сказали в комментариях выше, Вы просто настраиваете вывод каждый раз и повторно выполняете команду, что-то хотело бы следующую работу?
from threading import Timer
import subprocess
WAIT_TIME = 10.0
def check_cmd(cmd):
p = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
def _check():
if p.poll()!=0:
print cmd+" did not quit within the given time period."
# check whether the given process has exited WAIT_TIME
# seconds from now
Timer(WAIT_TIME, _check).start()
check_cmd('echo')
check_cmd('python')
код выше, когда выполнено, выводы:
python did not quit within the given time period.
единственный недостаток вышеупомянутого кода, о котором я могу думать, является потенциально перекрывающимися процессами, поскольку Вы продолжаете управлять check_cmd.
Вот что я придумал. Работает, когда вам нужно и не нужно тайм-аут для процесса p, но с полузанятым циклом.
def runCmd(cmd, timeout=None):
'''
Will execute a command, read the output and return it back.
@param cmd: command to execute
@param timeout: process timeout in seconds
@return: a tuple of three: first stdout, then stderr, then exit code
@raise OSError: on missing command or if a timeout was reached
'''
ph_out = None # process output
ph_err = None # stderr
ph_ret = None # return code
p = subprocess.Popen(cmd, shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
# if timeout is not set wait for process to complete
if not timeout:
ph_ret = p.wait()
else:
fin_time = time.time() + timeout
while p.poll() == None and fin_time > time.time():
time.sleep(1)
# if timeout reached, raise an exception
if fin_time < time.time():
# starting 2.6 subprocess has a kill() method which is preferable
# p.kill()
os.kill(p.pid, signal.SIGKILL)
raise OSError("Process timeout has been reached")
ph_ret = p.returncode
ph_out, ph_err = p.communicate()
return (ph_out, ph_err, ph_ret)