Пропустить утверждение, если требуется больше времени python [duplicate]

в отличие от коммитов вы можете легко удалять теги с удаленных, воссоздать их с именем автора, которое вы хотите

git tag -d <tag-name> 
git push origin :refs/tags/<tag-name>
git config --global user.name "John Doe"
git config --global user.email johndoe@example.com
git tag <tag-name> [commit]
git push origin <tag-name>
266
задан 4 revs, 2 users 92% 1 November 2015 в 01:18
поделиться

27 ответов

В Python 3.3 +:

from subprocess import STDOUT, check_output

output = check_output(cmd, stderr=STDOUT, timeout=seconds)

output представляет собой байтовую строку, содержащую объединенные stdout команды, данные stderr.

Этот код повышает значение CalledProcessError при ненулевом статусе выхода, как указано в тексте вопроса, в отличие от метода proc.communicate().

Я удалил shell=True, потому что он часто используется без необходимости. Вы всегда можете добавить его обратно, если cmd действительно требует его. Если вы добавите shell=True, то есть, если дочерний процесс порождает своих потомков; check_output() может вернуться намного позже, чем указывает таймаут, см. Ошибка тайм-аута подпроцесса .

Функция тайм-аута доступна на Python 2.x через subprocess32 backport модуля подпроцесса 3.2+.

126
ответ дан 4 revs, 2 users 89% 22 August 2018 в 17:45
поделиться
  • 1
    Действительно, поддержка тайм-аута подпроцесса существует в backport-файле subprocess32, который я поддерживаю для использования на Python 2. pypi.python.org/pypi/subprocess32 – gps 9 December 2012 в 06:07
  • 2
    @gps Sridhar попросил кросс-платформенное решение, в то время как ваш backport поддерживает только POSIX: когда я это пробовал, MSVC жаловался (ожидал) на отсутствие unistd.h :) – Shmil The Cat 12 March 2013 в 15:43
  • 3
    Если вам не нужен вывод, вы можете просто использовать subprocess.call. – Kyle Gibson 28 March 2013 в 18:46
  • 4
    +1 только для комментария shell=True. – tripleee 11 September 2014 в 15:57

Это решение убивает дерево процессов в случае оболочки = True, передает параметры процессу (или нет), имеет тайм-аут и получает вывод stdout, stderr и процесс обратного вызова (он использует psutil для kill_proc_tree) , Это было основано на нескольких решениях, размещенных в SO, включая jcollado's. Проводка в ответ на комментарии Ансона и юрида в ответ jcollado. Протестировано в Windows Srvr 2012 и Ubuntu 14.04. Обратите внимание, что для Ubuntu вам необходимо изменить вызов parent.children (...) parent.get_children (...).

def kill_proc_tree(pid, including_parent=True):
  parent = psutil.Process(pid)
  children = parent.children(recursive=True)
  for child in children:
    child.kill()
  psutil.wait_procs(children, timeout=5)
  if including_parent:
    parent.kill()
    parent.wait(5)

def run_with_timeout(cmd, current_dir, cmd_parms, timeout):
  def target():
    process = subprocess.Popen(cmd, cwd=current_dir, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)

    # wait for the process to terminate
    if (cmd_parms == ""):
      out, err = process.communicate()
    else:
      out, err = process.communicate(cmd_parms)
    errcode = process.returncode

  thread = Thread(target=target)
  thread.start()

  thread.join(timeout)
  if thread.is_alive():
    me = os.getpid()
    kill_proc_tree(me, including_parent=False)
    thread.join()
4
ответ дан 2 revs 22 August 2018 в 17:45
поделиться

К сожалению, я связан очень строгими политиками в отношении раскрытия исходного кода моим работодателем, поэтому я не могу предоставить фактический код. Но, по моему мнению, лучшим решением является создание подкласса, переопределяющего Popen.wait() для опроса вместо ожидания на неопределенный срок, и Popen.__init__ для принятия параметра таймаута. Как только вы это сделаете, все остальные Popen методы (которые вызывают wait) будут работать, как ожидалось, включая communicate.

0
ответ дан 2 revs, 2 users 67% 22 August 2018 в 17:45
поделиться

Я добавил решение с потоком из jcollado в мой модуль Python easyprocess .

Установка:

pip install easyprocess

Пример:

from easyprocess import Proc

# shell is not supported!
stdout=Proc('ping localhost').call(timeout=1.5).stdout
print stdout
4
ответ дан 2 revs, 2 users 83% 22 August 2018 в 17:45
поделиться

Вы можете сделать это, используя select

import subprocess
from datetime import datetime
from select import select

def call_with_timeout(cmd, timeout):
    started = datetime.now()
    sp = subprocess.Popen(cmd, stdout=subprocess.PIPE)
    while True:
        p = select([sp.stdout], [], [], timeout)
        if p[0]:
            p[0][0].read()
        ret = sp.poll()
        if ret is not None:
            return ret
        if (datetime.now()-started).total_seconds() > timeout:
            sp.kill()
            return None
2
ответ дан 2 revs, 2 users 89% 22 August 2018 в 17:45
поделиться
7
ответ дан 2 revs, 2 users 90% 22 August 2018 в 17:45
поделиться

Я изменил ответ sussudio. Теперь функция возвращает: (returncode, stdout, stderr, timeout) - stdout и stderr декодируется в строку utf-8

def kill_proc(proc, timeout):
  timeout["value"] = True
  proc.kill()

def run(cmd, timeout_sec):
  proc = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  timeout = {"value": False}
  timer = Timer(timeout_sec, kill_proc, [proc, timeout])
  timer.start()
  stdout, stderr = proc.communicate()
  timer.cancel()
  return proc.returncode, stdout.decode("utf-8"), stderr.decode("utf-8"), timeout["value"]
15
ответ дан 2 revs, 2 users 96% 22 August 2018 в 17:45
поделиться
43
ответ дан 3 revs, 3 users 91% 22 August 2018 в 17:45
поделиться

Если вы используете Unix,

import signal
  ...
class Alarm(Exception):
    pass

def alarm_handler(signum, frame):
    raise Alarm

signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(5*60)  # 5 minutes
try:
    stdoutdata, stderrdata = proc.communicate()
    signal.alarm(0)  # reset the alarm
except Alarm:
    print "Oops, taking too long!"
    # whatever else
76
ответ дан 3 revs, 3 users 95% 22 August 2018 в 17:45
поделиться
  • 1
    Ну, меня интересует кросс-платформенное решение, которое работает хотя бы на win / linux / mac. – Sridhar Ratnakumar 28 July 2009 в 02:52
  • 2
    Мне нравится этот подход на основе unix. В идеале можно было бы объединить это с подходом, специфичным для Windows (с использованием CreateProcess и Jobs) .. но на данный момент решение ниже простое, простое и работает так далеко. – Sridhar Ratnakumar 29 July 2009 в 20:43
  • 3
  • 4
    Это решение будет работать only_if signal.signal (signal.SIGALARM, alarm_handler) вызывается из основного потока. См. Документацию для сигнала – volatilevoid 19 December 2009 в 06:58
  • 5
    К сожалению, при запуске (в Linux) в контексте модуля Apache (например, mod_python, mod_perl или mod_php) я обнаружил, что использование сигналов и аварийных сигналов должно быть запрещено (предположительно потому, что они мешают собственной логике IPC Apache). Поэтому для достижения цели тайминга команды мне пришлось писать «родительские петли», которые запускают дочерний процесс, а затем сидят в цикле «sleep», наблюдая за часами (и, возможно, также контролируя выходные данные дочернего элемента). – Peter 29 July 2011 в 01:54

У меня возникла проблема в том, что я хотел завершить многопроцессорный подпроцесс, если потребовалось больше времени, чем заданная длина таймаута. Я хотел установить тайм-аут в Popen(), но это не сработало. Затем я понял, что Popen().wait() равен call(), и поэтому у меня возникла идея установить тайм-аут в рамках метода .wait(timeout=xxx), который, наконец, работал. Таким образом, я решил это так:

import os
import sys
import signal
import subprocess
from multiprocessing import Pool

cores_for_parallelization = 4
timeout_time = 15  # seconds

def main():
    jobs = [...YOUR_JOB_LIST...]
    with Pool(cores_for_parallelization) as p:
        p.map(run_parallel_jobs, jobs)

def run_parallel_jobs(args):
    # Define the arguments including the paths
    initial_terminal_command = 'C:\\Python34\\python.exe'  # Python executable
    function_to_start = 'C:\\temp\\xyz.py'  # The multithreading script
    final_list = [initial_terminal_command, function_to_start]
    final_list.extend(args)

    # Start the subprocess and determine the process PID
    subp = subprocess.Popen(final_list)  # starts the process
    pid = subp.pid

    # Wait until the return code returns from the function by considering the timeout. 
    # If not, terminate the process.
    try:
        returncode = subp.wait(timeout=timeout_time)  # should be zero if accomplished
    except subprocess.TimeoutExpired:
        # Distinguish between Linux and Windows and terminate the process if 
        # the timeout has been expired
        if sys.platform == 'linux2':
            os.kill(pid, signal.SIGTERM)
        elif sys.platform == 'win32':
            subp.terminate()

if __name__ == '__main__':
    main()
1
ответ дан 4 revs, 2 users 99% 22 August 2018 в 17:45
поделиться

Ответ jcollado можно упростить, используя класс threading.Timer :

import shlex
from subprocess import Popen, PIPE
from threading import Timer

def run(cmd, timeout_sec):
    proc = Popen(shlex.split(cmd), stdout=PIPE, stderr=PIPE)
    timer = Timer(timeout_sec, proc.kill)
    try:
        timer.start()
        stdout, stderr = proc.communicate()
    finally:
        timer.cancel()

# Examples: both take 1 second
run("sleep 1", 5)  # process ends normally at 1 second
run("sleep 5", 1)  # timeout happens at 1 second
88
ответ дан 4 revs, 3 users 53% 22 August 2018 в 17:45
поделиться
  • 1
    +1 для простого портативного решения. Вам не нужно lambda: t = Timer(timeout, proc.kill) – jfs 5 April 2014 в 22:43
  • 2
    +1 Это должен быть принятый ответ, потому что он не требует, чтобы процесс запуска был изменен. – Dave Branton 28 May 2015 в 22:18
  • 3
    Почему это требует лямбда? Не может ли использоваться метод bound p.kill без лямбда? – Danny Staple 5 August 2015 в 16:10
  • 4
    //, Вы хотели бы включить пример использования этого? – Nathan Basanese 2 September 2015 в 00:27
  • 5
    отличное решение, избегая is_alive – Massimo 6 November 2015 в 06:46
0
ответ дан Alexander Yakovlev 22 August 2018 в 17:45
поделиться
  • 1
    Этот декоратор использует signal.alarm, который недоступен в Windows. – dbn 14 December 2013 в 02:56

Я успешно использовал killableprocess в Windows, Linux и Mac. Если вы используете Cygwin Python, вам понадобится версия killableprocess OSAF, потому что иначе родные процессы Windows не будут убиты.

1
ответ дан Heikki Toivonen 22 August 2018 в 17:45
поделиться
  • 1
    Похоже, killableprocess не добавляет тайм-аут к вызову Popen.communicate (). – Wim Coenen 20 October 2009 в 18:44

Просто пытался написать что-то более простое.

#!/usr/bin/python

from subprocess import Popen, PIPE
import datetime
import time 

popen = Popen(["/bin/sleep", "10"]);
pid = popen.pid
sttime = time.time();
waittime =  3

print "Start time %s"%(sttime)

while True:
    popen.poll();
    time.sleep(1)
    rcode = popen.returncode
    now = time.time();
    if [ rcode is None ]  and  [ now > (sttime + waittime) ] :
        print "Killing it now"
        popen.kill()
-2
ответ дан Jabir Ahmed 22 August 2018 в 17:45
поделиться
  • 1
    time.sleep (1) - очень плохая идея - представьте, что вы хотите запустить много команд, которые занимают около 0.002 сек. Вам лучше подождать пока poll () (см. Выбор, для Linux epol recomended :) – ddzialak 9 May 2014 в 22:03

Я мало знаю о деталях низкого уровня; но, учитывая, что в python 2.6 API предлагает возможность ждать потоков и завершать процессы, как запустить процесс в отдельном потоке?

import subprocess, threading

class Command(object):
    def __init__(self, cmd):
        self.cmd = cmd
        self.process = None

    def run(self, timeout):
        def target():
            print 'Thread started'
            self.process = subprocess.Popen(self.cmd, shell=True)
            self.process.communicate()
            print 'Thread finished'

        thread = threading.Thread(target=target)
        thread.start()

        thread.join(timeout)
        if thread.is_alive():
            print 'Terminating process'
            self.process.terminate()
            thread.join()
        print self.process.returncode

command = Command("echo 'Process started'; sleep 2; echo 'Process finished'")
command.run(timeout=3)
command.run(timeout=1)

Вывод этого фрагмента на моей машине:

Thread started
Process started
Process finished
Thread finished
0
Thread started
Process started
Terminating process
Thread finished
-15

, где можно видеть, что при первом выполнении процесс завершился правильно (код возврата 0), а во втором - завершение процесса (код возврата -15).

Я не тестировал в окнах; но, помимо обновления команды примера, я думаю, что она должна работать, поскольку я не нашел в документации ничего, что говорит о том, что thread.join или process.terminate не поддерживается.

187
ответ дан jcollado 22 August 2018 в 17:45
поделиться
  • 1
    +1 За независимость от платформы. Я запустил это как в Linux, так и в Windows 7 (cygwin и простой python windows) - работает как ожидалось во всех трех случаях. – phooji 17 February 2011 в 01:27
  • 2
    Я немного изменил ваш код, чтобы иметь возможность передавать собственные Popen kwargs и помещать его в gist. Теперь он готов использовать многоцелевое назначение; gist.github.com/1306188 – kirpit 9 November 2011 в 15:07
  • 3
    Для любого, у кого возникла проблема @redice, этот вопрос может помочь. Короче говоря, если вы используете shell = True, оболочка становится дочерним процессом, который убивается, а его команда (дочерний элемент дочернего процесса) живет. – Anson 19 March 2013 в 02:11
  • 4
    Этот ответ не обеспечивает одинаковые функциональные возможности оригинала, так как он не возвращает stdout. – stephenbez 17 December 2013 в 18:39
  • 5
    thread.is_alive может привести к состоянию гонки. См. ostricher.com/2015/01/python-subprocess-with-timeout – ChaimKut 7 May 2015 в 12:56

Я не знаю, почему это не упоминается, но с Python 3.5 существует новая универсальная команда subprocess.run (которая предназначена для замены check_call, check_output ... ) и который имеет параметр timeout.

subprocess.run (args, *, stdin = None, input = None, stdout = None, stderr = None, shell = False, cwd = None, timeout = None, check = False, encoding = None, errors = None)

Run the command described by args. Wait for command to complete, then return a CompletedProcess instance.

Он вызывает исключение subprocess.TimeoutExpired, когда время ожидания истекло.

2
ответ дан Jean-François Fabre 22 August 2018 в 17:45
поделиться

Я реализовал то, что я мог бы собрать из нескольких из них. Это работает в Windows, и поскольку это вики сообщества, я полагаю, что я также поделился бы своим кодом:

class Command(threading.Thread):
    def __init__(self, cmd, outFile, errFile, timeout):
        threading.Thread.__init__(self)
        self.cmd = cmd
        self.process = None
        self.outFile = outFile
        self.errFile = errFile
        self.timed_out = False
        self.timeout = timeout

    def run(self):
        self.process = subprocess.Popen(self.cmd, stdout = self.outFile, \
            stderr = self.errFile)

        while (self.process.poll() is None and self.timeout > 0):
            time.sleep(1)
            self.timeout -= 1

        if not self.timeout > 0:
            self.process.terminate()
            self.timed_out = True
        else:
            self.timed_out = False

Затем из другого класса или файла:

        outFile =  tempfile.SpooledTemporaryFile()
        errFile =   tempfile.SpooledTemporaryFile()

        executor = command.Command(c, outFile, errFile, timeout)
        executor.daemon = True
        executor.start()

        executor.join()
        if executor.timed_out:
            out = 'timed out'
        else:
            outFile.seek(0)
            errFile.seek(0)
            out = outFile.read()
            err = errFile.read()

        outFile.close()
        errFile.close()
2
ответ дан joslinm 22 August 2018 в 17:45
поделиться
  • 1
    На самом деле это, вероятно, не работает. Функция terminate() отмечает поток как завершенный, но фактически не завершает поток! Я могу проверить это в * nix, но у меня нет компьютера Windows для тестирования. – dotancohen 6 October 2013 в 10:50

никого не удивил, используя timeout

timeout 5 ping -c 3 somehost

Это не будет работать для каждого примера использования, но если вы имеете дело с простым скриптом, это

Также доступен как gtimeout в coreutils через homebrew для пользователей Mac.

15
ответ дан Karsten 22 August 2018 в 17:45
поделиться
  • 1
    вы имеете в виду: proc = subprocess.Popen(['/usr/bin/timeout', str(timeout)] + cmd, ...). Есть ли команда timeout в Windows при запросе OP? – jfs 21 April 2015 в 09:18

Другой вариант - записать во временный файл, чтобы предотвратить блокировку stdout вместо необходимости опроса с помощью функции connect (). Это работало для меня, где другие ответы не делали; например, на окнах.

    outFile =  tempfile.SpooledTemporaryFile() 
    errFile =   tempfile.SpooledTemporaryFile() 
    proc = subprocess.Popen(args, stderr=errFile, stdout=outFile, universal_newlines=False)
    wait_remaining_sec = timeout

    while proc.poll() is None and wait_remaining_sec > 0:
        time.sleep(1)
        wait_remaining_sec -= 1

    if wait_remaining_sec <= 0:
        killProc(proc.pid)
        raise ProcessIncompleteError(proc, timeout)

    # read temp streams from start
    outFile.seek(0);
    errFile.seek(0);
    out = outFile.read()
    err = errFile.read()
    outFile.close()
    errFile.close()
9
ответ дан Matt 22 August 2018 в 17:45
поделиться
  • 1
    Кажется неполным - что такое tempfile? – spiderplant0 8 April 2015 в 12:26
  • 2
    Включить & quot; импорт tempfile & quot ;, & quot; время импорта & quot; и "shell = True" внутри "Popen" (будьте осторожны с «shell = True»)! – Eduardo Lucio 26 November 2015 в 22:47
import subprocess, optparse, os, sys, re, datetime, threading, time, glob, shutil, xml.dom.minidom, traceback

class OutputManager:
    def __init__(self, filename, mode, console, logonly):
        self.con = console
        self.logtoconsole = True
        self.logtofile = False

        if filename:
            try:
                self.f = open(filename, mode)
                self.logtofile = True
                if logonly == True:
                    self.logtoconsole = False
            except IOError:
                print (sys.exc_value)
                print ("Switching to console only output...\n")
                self.logtofile = False
                self.logtoconsole = True

    def write(self, data):
        if self.logtoconsole == True:
            self.con.write(data)
        if self.logtofile == True:
            self.f.write(data)
        sys.stdout.flush()

def getTimeString():
        return time.strftime("%Y-%m-%d", time.gmtime())

def runCommand(command):
    '''
    Execute a command in new thread and return the
    stdout and stderr content of it.
    '''
    try:
        Output = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True).communicate()[0]
    except Exception as e:
        print ("runCommand failed :%s" % (command))
        print (str(e))
        sys.stdout.flush()
        return None
    return Output

def GetOs():
    Os = ""
    if sys.platform.startswith('win32'):
        Os = "win"
    elif sys.platform.startswith('linux'):
        Os = "linux"
    elif sys.platform.startswith('darwin'):
        Os = "mac"
    return Os


def check_output(*popenargs, **kwargs):
    try:
        if 'stdout' in kwargs: 
            raise ValueError('stdout argument not allowed, it will be overridden.') 

        # Get start time.
        startTime = datetime.datetime.now()
        timeoutValue=3600

        cmd = popenargs[0]

        if sys.platform.startswith('win32'):
            process = subprocess.Popen( cmd, stdout=subprocess.PIPE, shell=True) 
        elif sys.platform.startswith('linux'):
            process = subprocess.Popen( cmd , stdout=subprocess.PIPE, shell=True ) 
        elif sys.platform.startswith('darwin'):
            process = subprocess.Popen( cmd , stdout=subprocess.PIPE, shell=True ) 

        stdoutdata, stderrdata = process.communicate( timeout = timeoutValue )
        retcode = process.poll()

        ####################################
        # Catch crash error and log it.
        ####################################
        OutputHandle = None
        try:
            if retcode >= 1:
                OutputHandle = OutputManager( 'CrashJob_' + getTimeString() + '.txt', 'a+', sys.stdout, False)
                OutputHandle.write( cmd )
                print (stdoutdata)
                print (stderrdata)
                sys.stdout.flush()
        except Exception as e:
            print (str(e))

    except subprocess.TimeoutExpired:
            ####################################
            # Catch time out error and log it.
            ####################################
            Os = GetOs()
            if Os == 'win':
                killCmd = "taskkill /FI \"IMAGENAME eq {0}\" /T /F"
            elif Os == 'linux':
                killCmd = "pkill {0)"
            elif Os == 'mac':
                # Linux, Mac OS
                killCmd = "killall -KILL {0}"

            runCommand(killCmd.format("java"))
            runCommand(killCmd.format("YouApp"))

            OutputHandle = None
            try:
                OutputHandle = OutputManager( 'KillJob_' + getTimeString() + '.txt', 'a+', sys.stdout, False)
                OutputHandle.write( cmd )
            except Exception as e:
                print (str(e))
    except Exception as e:
            for frame in traceback.extract_tb(sys.exc_info()[2]):
                        fname,lineno,fn,text = frame
                        print "Error in %s on line %d" % (fname, lineno)
-1
ответ дан PeterZhao 22 August 2018 в 17:45
поделиться

Вот мое решение, я использовал Thread и Event:

import subprocess
from threading import Thread, Event

def kill_on_timeout(done, timeout, proc):
    if not done.wait(timeout):
        proc.kill()

def exec_command(command, timeout):

    done = Event()
    proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    watcher = Thread(target=kill_on_timeout, args=(done, timeout, proc))
    watcher.daemon = True
    watcher.start()

    data, stderr = proc.communicate()
    done.set()

    return data, stderr, proc.returncode

В действии:

In [2]: exec_command(['sleep', '10'], 5)
Out[2]: ('', '', -9)

In [3]: exec_command(['sleep', '10'], 11)
Out[3]: ('', '', 0)
5
ответ дан rsk 22 August 2018 в 17:45
поделиться

, если вы используете python 2, попробуйте

import subprocess32

try:
    output = subprocess32.check_output(command, shell=True, timeout=3)
except subprocess32.TimeoutExpired as e:
    print e
3
ответ дан ThOong Ku 22 August 2018 в 17:45
поделиться
  • 1
    Вероятно, не работает в Windows, как задано в начальном вопросе – Jean-Francois T. 15 November 2016 в 07:35

После того, как вы поймете, что все машины, работающие с полным процессом, в * unix, вы легко найдете более простое решение:

Рассмотрим этот простой пример, как сделать timeoutable communication () meth с помощью select.select () (доступно почти каждый on * nix в настоящее время). Это также можно записать с помощью epoll / poll / kqueue, но вариант select.select () может быть хорошим примером для вас. И основные ограничения select.select () (speed и 1024 max fds) не применимы для вашей задачи.

Это работает под * nix, не создает потоки, не использует сигналы, может быть выделено из любой поток (не только основной) и достаточно быстрый, чтобы читать 250 мб / с данных из stdout на моей машине (i5 2.3ghz).

В конце есть проблема в joinsting stdout / stderr связи. Если у вас огромный выход программы, это может привести к большому использованию памяти. Но вы можете вызывать связь () несколько раз с меньшими тайм-аутами.

class Popen(subprocess.Popen):
    def communicate(self, input=None, timeout=None):
        if timeout is None:
            return subprocess.Popen.communicate(self, input)

        if self.stdin:
            # Flush stdio buffer, this might block if user
            # has been writing to .stdin in an uncontrolled
            # fashion.
            self.stdin.flush()
            if not input:
                self.stdin.close()

        read_set, write_set = [], []
        stdout = stderr = None

        if self.stdin and input:
            write_set.append(self.stdin)
        if self.stdout:
            read_set.append(self.stdout)
            stdout = []
        if self.stderr:
            read_set.append(self.stderr)
            stderr = []

        input_offset = 0
        deadline = time.time() + timeout

        while read_set or write_set:
            try:
                rlist, wlist, xlist = select.select(read_set, write_set, [], max(0, deadline - time.time()))
            except select.error as ex:
                if ex.args[0] == errno.EINTR:
                    continue
                raise

            if not (rlist or wlist):
                # Just break if timeout
                # Since we do not close stdout/stderr/stdin, we can call
                # communicate() several times reading data by smaller pieces.
                break

            if self.stdin in wlist:
                chunk = input[input_offset:input_offset + subprocess._PIPE_BUF]
                try:
                    bytes_written = os.write(self.stdin.fileno(), chunk)
                except OSError as ex:
                    if ex.errno == errno.EPIPE:
                        self.stdin.close()
                        write_set.remove(self.stdin)
                    else:
                        raise
                else:
                    input_offset += bytes_written
                    if input_offset >= len(input):
                        self.stdin.close()
                        write_set.remove(self.stdin)

            # Read stdout / stderr by 1024 bytes
            for fn, tgt in (
                (self.stdout, stdout),
                (self.stderr, stderr),
            ):
                if fn in rlist:
                    data = os.read(fn.fileno(), 1024)
                    if data == '':
                        fn.close()
                        read_set.remove(fn)
                    tgt.append(data)

        if stdout is not None:
            stdout = ''.join(stdout)
        if stderr is not None:
            stderr = ''.join(stderr)

        return (stdout, stderr)
2
ответ дан Vadim Fint 22 August 2018 в 17:45
поделиться
  • 1
    Это касается только половины проблемы Unix. – Spaceghost 30 August 2012 в 15:27

Предоставление команды Linux timeout не является плохим обходным решением, и это сработало для меня.

cmd = "timeout 20 "+ cmd
subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(output, err) = p.communicate()
1
ответ дан Vikram Hosakote 22 August 2018 в 17:45
поделиться
4
ответ дан 2 revs 5 November 2018 в 15:15
поделиться
0
ответ дан whi 5 November 2018 в 15:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: