Запрос Popen на подвесную машину с использованием ssh [duplicate]

Неопределенные символы для архитектуры x86_64: «_OBJC_CLASS _ $ _ xxx», на которые ссылается: objc-class-ref в yyy.o

Это обычно означает, что вы вызываете «xxx» "(это может быть каркас или класс) из класса" yyy ". Компилятор не может найти «xxx», чтобы произошла эта ошибка.

Вам нужно добавить отсутствующие файлы (в данном случае «xxx»), щелкнув правой кнопкой мыши по папке проекта в окне навигатора и коснитесь «Добавить файлы в» YourProjectName "" вариант.

Всплывающее окно откроет ваши файлы проекта в Finder. Там вы можете увидеть недостающие файлы и просто добавить их в свой проект. Не забудьте проверить флажок «Копировать предметы в случае необходимости». Удачи !!

265
задан 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% 18 August 2018 в 21:02
поделиться
  • 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 18 August 2018 в 21:02
поделиться

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

0
ответ дан 2 revs, 2 users 67% 18 August 2018 в 21:02
поделиться

Я добавил решение с потоком из 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% 18 August 2018 в 21:02
поделиться

Вы можете сделать это, используя 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% 18 August 2018 в 21:02
поделиться

timeout теперь поддерживается на call() и communicate() в модуле подпроцесса (как на Python3.3):

import subprocess

subprocess.call("command", timeout=20, shell=True)

Это вызовет команду и поднять исключение

subprocess.TimeoutExpired

, если команда не завершится через 20 секунд.

Затем вы можете обработать исключение, чтобы продолжить свой код, например:

try:
    subprocess.call("command", timeout=20, shell=True)
except subprocess.TimeoutExpired:
    # insert code here

Надеюсь, это поможет.

7
ответ дан 2 revs, 2 users 90% 18 August 2018 в 21:02
поделиться

Я изменил ответ 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% 18 August 2018 в 21:02
поделиться

Вот решение Alex Martelli как модуль с надлежащим убийством процесса. Другие подходы не работают, потому что они не используют proc.communicate (). Поэтому, если у вас есть процесс, который производит много результатов, он заполнит свой выходной буфер, а затем заблокирует, пока вы не прочитаете что-нибудь из него.

from os import kill
from signal import alarm, signal, SIGALRM, SIGKILL
from subprocess import PIPE, Popen

def run(args, cwd = None, shell = False, kill_tree = True, timeout = -1, env = None):
    '''
    Run a command with a timeout after which it will be forcibly
    killed.
    '''
    class Alarm(Exception):
        pass
    def alarm_handler(signum, frame):
        raise Alarm
    p = Popen(args, shell = shell, cwd = cwd, stdout = PIPE, stderr = PIPE, env = env)
    if timeout != -1:
        signal(SIGALRM, alarm_handler)
        alarm(timeout)
    try:
        stdout, stderr = p.communicate()
        if timeout != -1:
            alarm(0)
    except Alarm:
        pids = [p.pid]
        if kill_tree:
            pids.extend(get_process_children(p.pid))
        for pid in pids:
            # process might have died before getting to this line
            # so wrap to avoid OSError: no such process
            try: 
                kill(pid, SIGKILL)
            except OSError:
                pass
        return -9, '', ''
    return p.returncode, stdout, stderr

def get_process_children(pid):
    p = Popen('ps --no-headers -o pid --ppid %d' % pid, shell = True,
              stdout = PIPE, stderr = PIPE)
    stdout, stderr = p.communicate()
    return [int(p) for p in stdout.split()]

if __name__ == '__main__':
    print run('find /', shell = True, timeout = 3)
    print run('find', shell = True)
43
ответ дан 3 revs, 3 users 91% 18 August 2018 в 21:02
поделиться
  • 1
    Это не будет работать на окнах, а порядок функций будет отменен. – Hamish Grubijan 23 January 2011 в 19:15
  • 2
    Иногда это приводит к исключению, когда другой обработчик регистрируется на SIGALARM и убивает процесс до того, как он дойдет до «kill», добавив обход. Кстати, отличный рецепт! Я использовал это для запуска 50 000 багги-процессов до сих пор без замораживания или сбоя обертки обработки. – Yaroslav Bulatov 1 July 2011 в 22:02
  • 3
    Как это можно изменить для запуска в приложении с резьбой? Я пытаюсь использовать его изнутри рабочих потоков и получить ValueError: signal only works in main thread – wim 3 August 2011 в 08:18
  • 4
    @ Ярослав Булатов Спасибо за информацию. Каким было обходное решение, которое вы добавили для решения проблемы? – jpswain 10 August 2011 в 16:38
  • 5
    Просто добавлено & quot; try; catch & quot; блок, он внутри кода. BTW, в долгосрочной перспективе, это оказалось для меня проблемой, потому что вы можете установить только один обработчик SIGALARM, а другие процессы могут его сбросить. Здесь дается одно решение: stackoverflow.com/questions/6553423/… – Yaroslav Bulatov 11 August 2011 в 06:49

Если вы используете 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% 18 August 2018 в 21:02
поделиться
  • 1
    Ну, меня интересует кросс-платформенное решение, которое работает хотя бы на win / linux / mac. – Sridhar Ratnakumar 28 July 2009 в 02:52
  • 2
    Мне нравится этот подход на основе unix. В идеале можно было бы объединить это с подходом, специфичным для Windows (с использованием CreateProcess и Jobs) .. но на данный момент решение ниже простое, простое и работает так далеко. – Sridhar Ratnakumar 29 July 2009 в 20:43
  • 3
    Я добавил портативное решение, см. Мой ответ – flybywire 13 October 2009 в 09:16
  • 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% 18 August 2018 в 21:02
поделиться

Ответ 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% 18 August 2018 в 21:02
поделиться
  • 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

Существует идея подкласса класса Popen и расширения его с помощью некоторых простых декораторов методов. Назовем его ExpirablePopen.

from logging import error
from subprocess import Popen
from threading import Event
from threading import Thread


class ExpirablePopen(Popen):

    def __init__(self, *args, **kwargs):
        self.timeout = kwargs.pop('timeout', 0)
        self.timer = None
        self.done = Event()

        Popen.__init__(self, *args, **kwargs)

    def __tkill(self):
        timeout = self.timeout
        if not self.done.wait(timeout):
            error('Terminating process {} by timeout of {} secs.'.format(self.pid, timeout))
            self.kill()

    def expirable(func):
        def wrapper(self, *args, **kwargs):
            # zero timeout means call of parent method
            if self.timeout == 0:
                return func(self, *args, **kwargs)

            # if timer is None, need to start it
            if self.timer is None:
                self.timer = thr = Thread(target=self.__tkill)
                thr.daemon = True
                thr.start()

            result = func(self, *args, **kwargs)
            self.done.set()

            return result
        return wrapper

    wait = expirable(Popen.wait)
    communicate = expirable(Popen.communicate)


if __name__ == '__main__':
    from subprocess import PIPE

    print ExpirablePopen('ssh -T git@bitbucket.org', stdout=PIPE, timeout=1).communicate()
0
ответ дан Alexander Yakovlev 18 August 2018 в 21:02
поделиться
  • 1
    Этот декоратор использует signal.alarm, который недоступен в Windows. – dbn 14 December 2013 в 02:56

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

1
ответ дан Heikki Toivonen 18 August 2018 в 21:02
поделиться
  • 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()
-1
ответ дан Jabir Ahmed 18 August 2018 в 21:02
поделиться
  • 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 18 August 2018 в 21:02
поделиться
  • 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 18 August 2018 в 21:02
поделиться

Я реализовал то, что я мог бы собрать из нескольких из них. Это работает в 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 18 August 2018 в 21:02
поделиться
  • 1
    На самом деле это, вероятно, не работает. Функция terminate() отмечает поток как завершенный, но фактически не завершает поток! Я могу проверить это в * nix, но у меня нет компьютера Windows для тестирования. – dotancohen 6 October 2013 в 10:50

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

timeout 5 ping -c 3 somehost

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

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

15
ответ дан Karsten 18 August 2018 в 21:02
поделиться
  • 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 18 August 2018 в 21:02
поделиться
  • 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 18 August 2018 в 21:02
поделиться

Вот мое решение, я использовал 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 18 August 2018 в 21:02
поделиться

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

import subprocess32

try:
    output = subprocess32.check_output(command, shell=True, timeout=3)
except subprocess32.TimeoutExpired as e:
    print e
3
ответ дан ThOong Ku 18 August 2018 в 21:02
поделиться
  • 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 18 August 2018 в 21:02
поделиться
  • 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 18 August 2018 в 21:02
поделиться
4
ответ дан 2 revs 7 September 2018 в 05:00
поделиться
4
ответ дан 2 revs 30 October 2018 в 09:05
поделиться
Другие вопросы по тегам:

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