Korzystanie z modułu "podproces" z timeoutem
Oto Kod Pythona do uruchomienia dowolnego polecenia zwracającego jego dane stdout
lub wywołania wyjątku na niezerowych kodach wyjścia:
proc = subprocess.Popen(
cmd,
stderr=subprocess.STDOUT, # Merge stdout and stderr
stdout=subprocess.PIPE,
shell=True)
communicate
jest używane do oczekiwania na zakończenie procesu:
stdoutdata, stderrdata = proc.communicate()
Moduł subprocess
nie obsługuje timeout--możliwość zabicia procesu działającego przez więcej niż X liczbę sekund--dlatego communicate
może trwać wieczność.
Jaki jest najprostszy sposób implementacji timeoutów w programie Pythona przeznaczonym do pracy w systemie Windows a Linux?
30 answers
W Pythonie 3.3+:
from subprocess import STDOUT, check_output
output = check_output(cmd, stderr=STDOUT, timeout=seconds)
output
jest ciągiem bajtów, który zawiera scalone dane stdout, stderr polecenia.
check_output
podnosi CalledProcessError
na niezerowy status wyjścia, jak określono w tekście pytania, w przeciwieństwie do metody proc.communicate()
.
Usunąłem shell=True
ponieważ często jest używany niepotrzebnie. Zawsze możesz go dodać Z Powrotem, Jeśli cmd
rzeczywiście tego wymaga. Jeśli dodasz shell=True
, tzn. jeśli proces potomny wywoła własnych Potomków; check_output()
może powrócić znacznie później niż timeout wskazuje, patrz błąd limitu czasu Podprocesu .
Funkcja timeout jest dostępna w Pythonie 2.x przez subprocess32
backport modułu podprocesu 3.2+.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-20 14:47:36
Niewiele wiem o szczegółach niskiego poziomu, ale biorąc pod uwagę, że w python 2.6 API oferuje możliwość oczekiwania na wątki i zakończyć procesy, a co z uruchomieniem procesu w osobnym wątek?
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)
Wyjście tego fragmentu w mojej maszynie to:
Thread started
Process started
Process finished
Thread finished
0
Thread started
Process started
Terminating process
Thread finished
-15
Gdzie widać, że w pierwszym wykonaniu proces zakończone poprawnie( kod powrotu 0), natomiast w drugim proces został zakończony(kod powrotu -15).
Nie testowałem w windows; ale oprócz aktualizacji przykładu polecenie, myślę, że powinno działać, ponieważ nie znalazłem w dokumentuje wszystko, co mówi ten wątek.Dołącz lub przetworz.Zakończ nie jest obsługiwana.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-01-28 07:39:08
Odpowiedź Jcollado można uprościć używając wątku .Timer klasa:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-18 01:27:29
Jeśli jesteś na Unixie,
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-12 01:54:07
Oto rozwiązanie Alexa Martelli jako modułu z prawidłowym zabijaniem procesów. Inne podejścia nie działają, ponieważ nie używają proc.communicate (). Więc jeśli masz proces, który wytwarza dużo danych wyjściowych, wypełni swój bufor wyjściowy, a następnie zablokuje, aż coś z niego przeczytasz.
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-11 00:04:03
Zaskoczony nikt nie wspomniał o użyciu timeout
timeout 5 ping -c 3 somehost
To nie będzie działać dla każdego przypadku użycia oczywiście, ale jeśli masz do czynienia z prostym skryptem, to jest trudne do pokonania.
Dostępne również jako gtimeout w coreutils poprzez homebrew
dla użytkowników komputerów mac.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-21 04:43:41
Zmodyfikowałem sussudio odpowiedz Teraz funkcja zwraca: (returncode
, stdout
, stderr
, timeout
) - stdout
i stderr
jest dekodowane do utf-8 string
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"]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-28 16:59:18
timeout
jest teraz wspierane przez call()
i communicate()
w module podprocesowym (od Python3.3):
import subprocess
subprocess.call("command", timeout=20, shell=True)
Wywoła polecenie i wywoła wyjątek
subprocess.TimeoutExpired
Jeśli polecenie nie zakończy się po 20 sekundach.
Możesz następnie obsłużyć wyjątek, aby kontynuować kod, coś w stylu:
try:
subprocess.call("command", timeout=20, shell=True)
except subprocess.TimeoutExpired:
# insert code here
Mam nadzieję, że to pomoże.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-22 16:59:59
Nie wiem dlaczego nie jest wymieniany, ale od Pythona 3.5 JEST NOWY subprocess.run
polecenie uniwersalne (które ma zastąpić check_call
, check_output
...) i który ma również parametr timeout
.
Podproces.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.
Wyświetla wyjątek subprocess.TimeoutExpired
, gdy timeout wygasł.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-30 09:19:58
Inną opcją jest zapisanie do pliku tymczasowego, aby zapobiec blokowaniu stdout zamiast konieczności przeszukiwania za pomocą communicate (). To działało dla mnie tam, gdzie inne odpowiedzi nie; na przykład w windows.
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()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-10 12:51:15
Dodałem rozwiązanie z threadingiem z jcollado
do mojego modułu Pythona easyprocess.
Zainstaluj:
pip install easyprocess
Przykład:
from easyprocess import Proc
# shell is not supported!
stdout=Proc('ping localhost').call(timeout=1.5).stdout
print stdout
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-16 18:02:26
Oto moje rozwiązanie, używałem wątku i zdarzenia:
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
W akcji:
In [2]: exec_command(['sleep', '10'], 5)
Out[2]: ('', '', -9)
In [3]: exec_command(['sleep', '10'], 11)
Out[3]: ('', '', 0)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-02 19:59:19
Rozwiązaniem, którego używam jest prefiks polecenia powłoki z timelimit . Jeśli komand trwa zbyt długo, timelimit go zatrzyma, a Popen będzie miał kod zwrotny ustawiony przez timelimit. Jeśli jest > 128, oznacza to, że timelimit zabił proces.
Zobacz także podproces Pythona z timeoutem i dużym wyjściem (>64K)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:41
Jeśli używasz Pythona 2, Spróbuj
import subprocess32
try:
output = subprocess32.check_output(command, shell=True, timeout=3)
except subprocess32.TimeoutExpired as e:
print e
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-15 08:10:19
Prepending Linux command timeout
nie jest złe obejście i to działało dla mnie.
cmd = "timeout 20 "+ cmd
subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(output, err) = p.communicate()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-09 05:22:39
Zaimplementowałem to, co mogłem zebrać z kilku z nich. To działa w Windows, a ponieważ jest to wiki społeczności, pomyślałem, że podzielę się również moim kodem: {]}
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
Następnie z innej klasy lub pliku:
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()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-02 18:47:14
Gdy zrozumiesz pełną obsługę maszyn w *Unixie, łatwo znajdziesz prostsze rozwiązanie:
Rozważ ten prosty przykład, jak sprawić, by timeoutable communicate() meth za pomocą select.select () (dostępne obecnie na *nix). Można to również zapisać za pomocą epoll / poll/kqueue, ale wybrać.wariant select() może być dla Ciebie dobrym przykładem. I główne ograniczenia select.select () (speed i 1024 max fds) nie nadają się do zastosowania w twoim zadaniu.
To działa pod *nix, nie tworzy wątków, nie używa sygnałów, może być pobierany z dowolnego wątku (nie tylko głównego) i szybko można odczytać 250MB / s danych ze stdout na moim komputerze (i5 2.3 ghz).
Jest problem w join ' ING stdout/stderr na końcu komunikacji. Jeśli masz ogromną wydajność programu, może to prowadzić do dużego zużycia pamięci. Można jednak wywołać metodę communicate() kilka razy z mniejszymi timeoutami.
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-11 13:46:13
Możesz to zrobić używając 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-01 04:08:24
Używałem killableprocess pomyślnie na Windows, Linux i Mac. Jeśli używasz Pythona Cygwin, będziesz potrzebował wersji killableprocess OSAFA, ponieważ w przeciwnym razie natywne procesy Windows nie zostaną zabite.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-12 23:15:47
Chociaż nie oglądałem go szeroko, ten dekorator , który znalazłem w ActiveState, wydaje się być całkiem przydatny do tego typu rzeczy. Wraz z subprocess.Popen(..., close_fds=True)
, przynajmniej jestem gotowy do tworzenia skryptów powłokowych w Pythonie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-24 01:42:21
To rozwiązanie zabija drzewo procesów w przypadku shell = True, przekazuje parametry procesowi (lub nie), ma limit czasu i pobiera stdout, stderr i wynik procesu wywołania zwrotnego (używa psutil do kill_proc_tree). Było to oparte na kilku rozwiązaniach opublikowanych w SO, w tym jcollado 's. Posting in response to comments by Anson and jradice in jcollado' s answer. Testowane w systemie Windows Srvr 2012 i Ubuntu 14.04. Pamiętaj, że w Ubuntu musisz zmienić rodzica.dzieci(...) telefon do rodzica.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()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-01 20:13:52
Jest pomysł, aby podklasować klasę Popen i rozszerzyć ją za pomocą prostych dekoratorów. Nazwijmy to 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 [email protected]', stdout=PIPE, timeout=1).communicate()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-19 12:18:44
Miałem problem, że chciałem zakończyć podproces wielowątkowy, jeśli trwało to dłużej niż określony czas. Chciałem ustawić timeout w Popen()
, ale nie zadziałało. Potem zdałem sobie sprawę, że {[2] } jest równe call()
i wpadłem na pomysł, aby ustawić timeout w metodzie .wait(timeout=xxx)
, która w końcu zadziałała. Tak więc rozwiązałem to w ten sposób:
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()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-19 16:21:23
Python 2.7
import time
import subprocess
def run_command(cmd, timeout=0):
start_time = time.time()
df = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while timeout and df.poll() == None:
if time.time()-start_time >= timeout:
df.kill()
return -1, ""
output = '\n'.join(df.communicate()).strip()
return df.returncode, output
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-08 00:11:38
Niestety, jestem związany bardzo surowymi zasadami dotyczącymi ujawniania kodu źródłowego przez mojego pracodawcę, więc nie mogę podać rzeczywistego kodu. Ale jak na mój gust najlepszym rozwiązaniem jest utworzenie podklasy nadrzędnej Popen.wait()
do ankiety zamiast oczekiwania w nieskończoność i Popen.__init__
do zaakceptowania parametru timeout. Gdy to zrobisz, wszystkie inne metody Popen
(wywołujące wait
) będą działać zgodnie z oczekiwaniami, w tym communicate
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-01 21:11:09
Https://pypi.python.org/pypi/python-subprocess2 dostarcza rozszerzenia do modułu podprocesu, które pozwalają czekać do określonego czasu, w przeciwnym razie zakończyć.
Więc, aby odczekać do 10 sekund na zakończenie procesu, w przeciwnym razie zabić:
pipe = subprocess.Popen('...')
timeout = 10
results = pipe.waitOrTerminate(timeout)
Jest to zgodne zarówno z windows, jak i unix. "results" jest słownikiem, zawiera "returnCode", który jest zwrotem aplikacji (lub żadnego, jeśli musiała zostać zabita), a także "actionTaken". które będą "SUBPROCESS2_PROCESS_COMPLETED", jeśli proces zakończył się normalnie, lub maska "SUBPROCESS2_PROCESS_TERMINATED" i SUBPROCESS2_PROCESS_KILLED w zależności od podjętych działań (patrz dokumentacja po pełne szczegóły)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-25 13:52:16
W Pythonie 2.6+ użyj gevent
from gevent.subprocess import Popen, PIPE, STDOUT
def call_sys(cmd, timeout):
p= Popen(cmd, shell=True, stdout=PIPE)
output, _ = p.communicate(timeout=timeout)
assert p.returncode == 0, p. returncode
return output
call_sys('./t.sh', 2)
# t.sh example
sleep 5
echo done
exit 1
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-01 12:15:03
Przykład przechwyconego wyjścia po timeout testowanego w Pythonie 3.7.8:
try:
return subprocess.run(command, shell=True, capture_output=True, timeout=20, cwd=cwd, universal_newlines=True)
except subprocess.TimeoutExpired as e:
print(e.output.decode(encoding="utf-8", errors="ignore"))
assert False;
Podproces wyjątku.TimeoutExpired ma wyjście i inne elementy:
Cmd-polecenie, które zostało użyte do wywołania procesu potomnego.
Timeout-limit czasu w sekundach.
Output-wyjście procesu potomnego, jeśli zostało przechwycone przez run () lub check_output (). W Przeciwnym Razie, Żaden.
Stdout-Alias dla wyjścia, dla symetrii ze stderr.
Stderr-wyjście stderr dziecka proces, jeśli został przechwycony przez run (). W Przeciwnym Razie, Żaden.
Więcej informacji: https://docs.python.org/3/library/subprocess.html#subprocess.TimeoutExpired
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-26 18:04:54
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-18 06:09:01
Próbowałem napisać coś prostszego.
#!/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()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-05 21:01:52