Aqui está o código Python para executar um comando arbitrário retornando seus stdout
dados ou gerar uma exceção em códigos de saída diferentes de zero:
proc = subprocess.Popen(
cmd,
stderr=subprocess.STDOUT, # Merge stdout and stderr
stdout=subprocess.PIPE,
shell=True)
communicate
é usado para aguardar a saída do processo:
stdoutdata, stderrdata = proc.communicate()
O subprocess
módulo não suporta tempo limite - capacidade de interromper um processo em execução por mais de X número de segundos - portanto,communicate
pode levar uma eternidade para ser executada.
Qual é a maneira mais simples de implementar tempos limite em um programa Python para rodar no Windows e Linux?
python
multithreading
timeout
subprocess
Sridhar Ratnakumar
fonte
fonte
Respostas:
No Python 3.3 ou superior:
output
é uma sequência de bytes que contém os dados stdout e stderr mesclados do comando.check_output
aumentaCalledProcessError
no status de saída diferente de zero, conforme especificado no texto da pergunta, diferenteproc.communicate()
método.Eu removi
shell=True
porque muitas vezes é usado desnecessariamente. Você sempre pode adicioná-lo de volta, secmd
necessário. Se você adicionarshell=True
, isto é, se o processo filho gerar seus próprios descendentes;check_output()
pode retornar muito mais tarde do que o tempo limite indica, consulte Falha no tempo limite do subprocesso .O recurso de tempo limite está disponível no Python 2.x através do
subprocess32
backport do módulo do subprocesso 3.2+.fonte
check_output()
é a maneira preferida de obter saída (ela retorna a saída diretamente, não ignora erros, está disponível desde sempre). 2-run()
é mais flexível, masrun()
ignora o erro por padrão e requer etapas adicionais para obter a saída 3-check_output()
é implementado em termos derun()
e, portanto, aceita a maioria dos mesmos argumentos. 4- nit:capture_output
está disponível desde 3.7, não 3.5Não sei muito sobre os detalhes de baixo nível; mas, como no python 2.6 a API oferece a capacidade de aguardar threads e finalizar processos, que tal executar o processo em um thread separado?
A saída desse trecho na minha máquina é:
onde se percebe que, na primeira execução, o processo foi finalizado corretamente (código de retorno 0), enquanto na segunda o processo foi finalizado (código de retorno -15).
Eu não testei no Windows; mas, além de atualizar o comando de exemplo, acho que deve funcionar, pois não encontrei na documentação nada que diga que thread.join ou process.terminate não é suportado.
fonte
A resposta de jcollado pode ser simplificada usando o classe threading.Timer :
fonte
lambda
:t = Timer(timeout, proc.kill)
timer.isAlive()
antestimer.cancel()
significa que terminou normalmenteSe você está no Unix,
fonte
Aqui está a solução de Alex Martelli como um módulo com a eliminação adequada do processo. As outras abordagens não funcionam porque não usam proc.communicate (). Portanto, se você tiver um processo que produz muita saída, ele preenche seu buffer de saída e bloqueia até você ler algo sobre ele.
fonte
ValueError: signal only works in main thread
Eu modifiquei a resposta do sussudio . Agora função retorna: (
returncode
,stdout
,stderr
,timeout
) -stdout
estderr
é decodificado para utf-8 cordafonte
surpreendeu ninguém mencionou usando
timeout
timeout 5 ping -c 3 somehost
Obviamente, isso não funciona em todos os casos de uso, mas se você estiver lidando com um script simples, é difícil de superar.
Também disponível como gtimeout no coreutils via
homebrew
para usuários de mac.fonte
proc = subprocess.Popen(['/usr/bin/timeout', str(timeout)] + cmd, ...)
. Existetimeout
comando no Windows como o OP pede?timeout
agora é suportado porcall()
ecommunicate()
no módulo subprocesso (a partir do Python3.3):Isso chamará o comando e gerará a exceção
se o comando não terminar após 20 segundos.
Você pode manipular a exceção para continuar seu código, algo como:
Espero que isto ajude.
fonte
timeout
parâmetro . Embora mencioná-lo mais uma vez não faria mal.Outra opção é gravar em um arquivo temporário para evitar o bloqueio do stdout em vez de precisar pesquisar com o communic (). Isso funcionou para mim, onde as outras respostas não; por exemplo no windows.
fonte
Eu não sei por que não é mencionado, mas desde o Python 3.5, há um novo
subprocess.run
comando universal (que deve substituircheck_call
,check_output
...) e que possui otimeout
parâmetro.Isso gera uma
subprocess.TimeoutExpired
exceção quando o tempo limite termina.fonte
Aqui está a minha solução, eu estava usando Thread e Evento:
Em ação:
fonte
A solução que eu uso é prefixar o comando shell com timelimit . Se o comando demorar muito, o timelimit o interromperá e o Popen terá um código de retorno definido por timelimit. Se for> 128, significa que o limite de tempo interrompeu o processo.
Consulte também subprocesso python com tempo limite e saída grande (> 64K)
fonte
timeout
- packages.ubuntu.com/search?keywords=timeout - mas nem funciona no Windows, funciona?Eu adicionei a solução com threading do
jcollado
meu módulo Python easyprocess .Instalar:
Exemplo:
fonte
se você estiver usando python 2, tente
fonte
Anexar o comando Linux
timeout
não é uma solução alternativa ruim e funcionou para mim.fonte
Eu implementei o que pude reunir de alguns deles. Isso funciona no Windows e, como esse é um wiki da comunidade, acho que eu também compartilharia meu código:
Em seguida, de outra classe ou arquivo:
fonte
terminate()
função marca um segmento como finalizado, mas na verdade não finaliza o segmento! Posso verificar isso no * nix, mas não tenho um computador Windows para testar.Depois de entender o processo completo de máquinas em * unix, você encontrará facilmente uma solução mais simples:
Considere este exemplo simples de como tornar o método communic () com tempo limite, usando select.select () (disponível quase em todo lugar no * nix atualmente). Isso também pode ser escrito com epoll / poll / kqueue, mas a variante select.select () pode ser um bom exemplo para você. E as principais limitações do select.select () (speed e 1024 max fds) não são aplicáveis à sua tarefa.
Isso funciona no * nix, não cria threads, não usa sinais, pode ser lançado a partir de qualquer thread (não apenas principal) e rápido o suficiente para ler 250mb / s de dados do stdout na minha máquina (i5 2.3ghz).
Há um problema ao ingressar no stdout / stderr no final da comunicação. Se você tiver uma saída enorme de programa, isso poderá levar ao grande uso de memória. Mas você pode ligar para communic () várias vezes com tempos limite menores.
fonte
Você pode fazer isso usando
select
fonte
Eu usei killableprocess com sucesso no Windows, Linux e Mac. Se você estiver usando o Cygwin Python, precisará da versão do killableprocess da OSAF porque, caso contrário, os processos nativos do Windows não serão mortos.
fonte
Embora eu não tenha examinado isso extensivamente, esse decorador que encontrei no ActiveState parece ser bastante útil para esse tipo de coisa. Junto com
subprocess.Popen(..., close_fds=True)
, pelo menos estou pronto para scripts de shell em Python.fonte
Essa solução mata a árvore do processo em caso de shell = True, passa parâmetros para o processo (ou não), tem um tempo limite e obtém a saída stdout, stderr e process da chamada de retorno (usa psutil para o kill_proc_tree). Isso foi baseado em várias soluções publicadas no SO, incluindo o jcollado's. Postagem em resposta aos comentários de Anson e jradice na resposta de jcollado. Testado no Windows Srvr 2012 e Ubuntu 14.04. Observe que, para o Ubuntu, você precisa alterar a chamada parent.children (...) para parent.get_children (...).
fonte
Existe uma idéia para subclassificar a classe Popen e estendê-la com alguns decoradores simples de métodos. Vamos chamá-lo de ExpirablePopen.
fonte
Tive o problema de querer encerrar um subprocesso de multithreading se demorasse mais que um determinado tempo limite. Eu queria definir um tempo limite
Popen()
, mas não funcionou. Então, percebi quePopen().wait()
é igual a,call()
e tive a ideia de definir um tempo limite dentro do.wait(timeout=xxx)
método, que finalmente funcionou. Assim, resolvi-o desta maneira:fonte
Infelizmente, estou vinculado a políticas muito rigorosas sobre a divulgação do código fonte pelo meu empregador, portanto não posso fornecer o código real. Mas, para meu gosto, a melhor solução é criar uma subclasse substituindo
Popen.wait()
a pesquisa em vez de esperar indefinidamente ePopen.__init__
aceitar um parâmetro de tempo limite. Depois de fazer isso, todos os outrosPopen
métodos (que chamamwait
) funcionarão conforme o esperado, incluindocommunicate
.fonte
https://pypi.python.org/pypi/python-subprocess2 fornece extensões ao módulo de subprocessos, que permitem que você espere até um determinado período de tempo, caso contrário, será encerrado.
Portanto, espere até 10 segundos para o processo terminar, caso contrário, mate:
Isso é compatível com Windows e Unix. "results" é um dicionário, contém "returnCode", que é o retorno do aplicativo (ou None, se ele tiver que ser morto), além de "actionTaken". que será "SUBPROCESS2_PROCESS_COMPLETED" se o processo for concluído normalmente ou uma máscara de "SUBPROCESS2_PROCESS_TERMINATED" e SUBPROCESS2_PROCESS_KILLED, dependendo da ação executada (consulte a documentação para obter detalhes completos)
fonte
para python 2.6+, use gevent
fonte
python 2.7
fonte
fonte
Estava apenas tentando escrever algo mais simples.
fonte