Неопределенные символы для архитектуры x86_64: «_OBJC_CLASS _ $ _ xxx», на которые ссылается: objc-class-ref в yyy.o
blockquote>Это обычно означает, что вы вызываете «xxx» "(это может быть каркас или класс) из класса" yyy ". Компилятор не может найти «xxx», чтобы произошла эта ошибка.
Вам нужно добавить отсутствующие файлы (в данном случае «xxx»), щелкнув правой кнопкой мыши по папке проекта в окне навигатора и коснитесь «Добавить файлы в» YourProjectName "" вариант.
Всплывающее окно откроет ваши файлы проекта в Finder. Там вы можете увидеть недостающие файлы и просто добавить их в свой проект. Не забудьте проверить флажок «Копировать предметы в случае необходимости». Удачи !!
В 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+.
Это решение убивает дерево процессов в случае оболочки = 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()
timeout
- packages.ubuntu.com/search?keywords=timeout - но ни один из них не работает в Windows, не так ли?
– Sridhar Ratnakumar
16 December 2011 в 20:00
К сожалению, я связан очень строгими политиками в отношении раскрытия исходного кода моим работодателем, поэтому я не могу предоставить фактический код. Но, по моему мнению, лучшим решением является создание подкласса, переопределяющего Popen.wait()
для опроса вместо ожидания на неопределенный срок, и Popen.__init__
для принятия параметра таймаута. Как только вы это сделаете, все остальные Popen
методы (которые вызывают wait
) будут работать, как ожидалось, включая communicate
.
Я добавил решение с потоком из 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
Вы можете сделать это, используя 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
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
Надеюсь, это поможет.
timeout
. Хотя упоминание об этом еще раз не повредит.
– jfs
23 February 2015 в 03:43
Я изменил ответ 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"]
Вот решение 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)
ValueError: signal only works in main thread
– wim
3 August 2011 в 08:18
Если вы используете 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
У меня возникла проблема в том, что я хотел завершить многопроцессорный подпроцесс, если потребовалось больше времени, чем заданная длина таймаута. Я хотел установить тайм-аут в 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()
Ответ 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
lambda
: t = Timer(timeout, proc.kill)
– jfs
5 April 2014 в 22:43
Существует идея подкласса класса 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()
Хотя я не смотрел на него широко, этот декоратор , который я нашел в ActiveState, кажется довольно полезным для такого рода вещей. Наряду с subprocess.Popen(..., close_fds=True)
, по крайней мере, я готов для сценариев оболочки в Python.
Я успешно использовал killableprocess в Windows, Linux и Mac. Если вы используете Cygwin Python, вам понадобится версия killableprocess OSAF, потому что иначе родные процессы Windows не будут убиты.
Просто пытался написать что-то более простое.
#!/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()
Я мало знаю о деталях низкого уровня; но, учитывая, что в 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 не поддерживается.
Я не знаю, почему это не упоминается, но с 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
, когда время ожидания истекло.
Я реализовал то, что я мог бы собрать из нескольких из них. Это работает в 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()
terminate()
отмечает поток как завершенный, но фактически не завершает поток! Я могу проверить это в * nix, но у меня нет компьютера Windows для тестирования.
– dotancohen
6 October 2013 в 10:50
никого не удивил, используя timeout
timeout 5 ping -c 3 somehost
Это не будет работать для каждого примера использования, но если вы имеете дело с простым скриптом, это
Также доступен как gtimeout в coreutils через homebrew
для пользователей Mac.
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()
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)
Вот мое решение, я использовал 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)
, если вы используете python 2, попробуйте
import subprocess32
try:
output = subprocess32.check_output(command, shell=True, timeout=3)
except subprocess32.TimeoutExpired as e:
print e
После того, как вы поймете, что все машины, работающие с полным процессом, в * 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)
Предоставление команды Linux timeout
не является плохим обходным решением, и это сработало для меня.
cmd = "timeout 20 "+ cmd
subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(output, err) = p.communicate()
shell=True
. – tripleee 11 September 2014 в 15:57