Voici le code Python pour exécuter une commande arbitraire renvoyant ses stdout
données, ou déclencher une exception sur les codes de sortie non nuls:
proc = subprocess.Popen(
cmd,
stderr=subprocess.STDOUT, # Merge stdout and stderr
stdout=subprocess.PIPE,
shell=True)
communicate
est utilisé pour attendre la fin du processus:
stdoutdata, stderrdata = proc.communicate()
Le subprocess
module ne prend pas en charge le délai d'expiration - possibilité de tuer un processus en cours d'exécution pendant plus de X secondes - par conséquent, l' communicate
exécution peut prendre une éternité.
Quelle est la manière la plus simple d'implémenter des délais d'attente dans un programme Python destiné à s'exécuter sur Windows et Linux?
python
multithreading
timeout
subprocess
Sridhar Ratnakumar
la source
la source
Réponses:
En Python 3.3+:
output
est une chaîne d'octets qui contient les données stderout, stderr fusionnées de la commande.check_output
augmenteCalledProcessError
le statut de sortie non nul comme spécifié dans le texte de la question contrairement à laproc.communicate()
méthode.J'ai supprimé
shell=True
car il est souvent utilisé inutilement. Vous pouvez toujours le rajouter si cela estcmd
vraiment nécessaire. Si vous ajoutezshell=True
ie, si le processus enfant engendre ses propres descendants;check_output()
peut retourner beaucoup plus tard que le délai indiqué, voir Échec du délai d'expiration du sous - processus .La fonction de timeout est disponible sur Python 2.x via le
subprocess32
backport du module de sous-processus 3.2+.la source
check_output()
est le moyen préféré pour obtenir la sortie (il renvoie la sortie directement, n'ignore pas les erreurs, il est disponible depuis toujours). 2-run()
est plus flexible maisrun()
ignore l'erreur par défaut et nécessite des étapes supplémentaires pour obtenir la sortie 3-check_output()
est implémenté en termes derun()
et accepte donc la plupart des mêmes arguments. 4- nit:capture_output
est disponible depuis la 3.7, pas la 3.5Je ne connais pas grand-chose aux détails de bas niveau; mais, étant donné qu'en python 2.6, l'API offre la possibilité d'attendre les threads et de terminer les processus, qu'en est-il de l'exécution du processus dans un thread séparé?
La sortie de cet extrait dans ma machine est:
où l'on peut voir que, dans la première exécution, le processus s'est terminé correctement (code retour 0), tandis que dans la seconde le processus a été terminé (code retour -15).
Je n'ai pas testé sous Windows; mais, à part mettre à jour l'exemple de commande, je pense que cela devrait fonctionner car je n'ai trouvé dans la documentation rien qui dise que thread.join ou process.terminate n'est pas pris en charge.
la source
La réponse de jcollado peut être simplifiée en utilisant la classe threading.Timer :
la source
lambda
:t = Timer(timeout, proc.kill)
timer.isAlive()
avanttimer.cancel()
signifie que cela s'est terminé normalementSi vous êtes sous Unix,
la source
Voici la solution d'Alex Martelli en tant que module avec destruction de processus appropriée. Les autres approches ne fonctionnent pas car elles n'utilisent pas proc.communicate (). Donc, si vous avez un processus qui produit beaucoup de sortie, il remplira son tampon de sortie, puis se bloquera jusqu'à ce que vous en lisiez quelque chose.
la source
ValueError: signal only works in main thread
J'ai modifié la réponse de sussudio . Maintenant , la fonction retourne: (
returncode
,stdout
,stderr
,timeout
) -stdout
etstderr
est décodé à chaîne utf-8la source
personne surpris de mentionner en utilisant
timeout
timeout 5 ping -c 3 somehost
Cela ne fonctionnera évidemment pas pour chaque cas d'utilisation, mais si vous traitez avec un script simple, c'est difficile à battre.
Également disponible en tant que gtimeout dans coreutils via
homebrew
pour les utilisateurs de mac.la source
proc = subprocess.Popen(['/usr/bin/timeout', str(timeout)] + cmd, ...)
. Existe-t-il unetimeout
commande sous Windows comme le demande OP?timeout
est désormais pris en charge parcall()
etcommunicate()
dans le module de sous-processus (à partir de Python3.3):Cela appellera la commande et déclenchera l'exception
si la commande ne se termine pas après 20 secondes.
Vous pouvez ensuite gérer l'exception pour continuer votre code, quelque chose comme:
J'espère que cela t'aides.
la source
timeout
paramètre . Bien que le mentionner une fois de plus ne ferait pas de mal.Une autre option consiste à écrire dans un fichier temporaire pour éviter le blocage de stdout au lieu de devoir interroger avec communic (). Cela a fonctionné pour moi là où les autres réponses n'ont pas fonctionné; par exemple sur les fenêtres.
la source
Je ne sais pas pourquoi cela n'est pas mentionné mais depuis Python 3.5, il y a une nouvelle
subprocess.run
commande universelle (qui est destinée à remplacercheck_call
,check_output
...) et qui a aussi letimeout
paramètre.Il déclenche une
subprocess.TimeoutExpired
exception lorsque le délai est expiré.la source
Voici ma solution, j'utilisais Thread et Event:
En action:
la source
La solution que j'utilise est de préfixer la commande shell avec timelimit . Si la commande prend trop de temps, timelimit l'arrêtera et Popen aura un code retour défini par timelimit. Si elle est> 128, cela signifie que la limite de temps a tué le processus.
Voir aussi sous-processus python avec timeout et grande sortie (> 64 Ko)
la source
timeout
- packages.ubuntu.com/search?keywords=timeout - mais aucun ne fonctionne sous Windows, n'est-ce pas?J'ai ajouté la solution avec le threading de
jcollado
à mon module Python easyprocess .Installer:
Exemple:
la source
si vous utilisez python 2, essayez-le
la source
Faire précéder la commande Linux
timeout
n'est pas une mauvaise solution de contournement et cela a fonctionné pour moi.la source
J'ai mis en œuvre ce que j'ai pu recueillir à partir de quelques-uns d'entre eux. Cela fonctionne sous Windows, et comme il s'agit d'un wiki communautaire, je pense que je partagerais également mon code:
Puis à partir d'une autre classe ou d'un autre fichier:
la source
terminate()
fonction marque un thread comme terminé, mais ne termine pas réellement le thread! Je peux le vérifier dans * nix, mais je n'ai pas d'ordinateur Windows pour tester.Une fois que vous aurez compris toutes les machines en cours d'exécution dans * unix, vous trouverez facilement une solution plus simple:
Considérez cet exemple simple comment rendre la meth communicable () expirable en utilisant select.select () (disponible presque partout sur * nix de nos jours). Cela peut également être écrit avec epoll / poll / kqueue, mais la variante select.select () pourrait être un bon exemple pour vous. Et les limitations majeures de select.select () (vitesse et 1024 max fds) ne sont pas applicables à votre tâche.
Cela fonctionne sous * nix, ne crée pas de threads, n'utilise pas de signaux, peut être lancé à partir de n'importe quel thread (non seulement principal) et assez rapide pour lire 250 Mo / s de données depuis la sortie standard de ma machine (i5 2,3 GHz).
Il y a un problème pour joindre stdout / stderr à la fin de la communication. Si vous avez une sortie de programme énorme, cela pourrait entraîner une grande utilisation de la mémoire. Mais vous pouvez appeler plusieurs fois communic () avec des délais plus courts.
la source
Vous pouvez le faire en utilisant
select
la source
J'ai utilisé killableprocess avec succès sur Windows, Linux et Mac. Si vous utilisez Cygwin Python, vous aurez besoin de la version OSAF de killableprocess car sinon les processus Windows natifs ne seront pas tués.
la source
Bien que je ne l'ai pas beaucoup examiné, ce décorateur que j'ai trouvé à ActiveState semble être très utile pour ce genre de chose. Parallèlement
subprocess.Popen(..., close_fds=True)
, au moins je suis prêt pour l'écriture de scripts shell en Python.la source
Cette solution tue l'arborescence des processus en cas de shell = True, transmet les paramètres au processus (ou non), a un délai d'attente et obtient la sortie stdout, stderr et process du rappel (elle utilise psutil pour le kill_proc_tree). Cela était basé sur plusieurs solutions publiées dans SO, y compris celles de jcollado. Publication en réponse aux commentaires d'Anson et de jradice dans la réponse de jcollado. Testé sous Windows Srvr 2012 et Ubuntu 14.04. Veuillez noter que pour Ubuntu, vous devez remplacer l'appel parent.children (...) par parent.get_children (...).
la source
Il y a une idée de sous-classer la classe Popen et de l'étendre avec des décorateurs de méthode simples. Appelons-le ExpirablePopen.
la source
J'ai eu le problème que je voulais mettre fin à un sous-processus multithreading si cela prenait plus de temps qu'une durée d'expiration donnée. Je voulais définir un délai d'attente
Popen()
, mais cela n'a pas fonctionné. Ensuite, j'ai réalisé quePopen().wait()
c'est égal àcall()
et j'ai donc eu l'idée de définir un timeout dans la.wait(timeout=xxx)
méthode, qui a finalement fonctionné. Ainsi, je l'ai résolu de cette façon:la source
Malheureusement, je suis lié par des politiques très strictes sur la divulgation du code source par mon employeur, donc je ne peux pas fournir le code réel. Mais à mon goût, la meilleure solution est de créer une sous-classe remplaçant
Popen.wait()
pour interroger au lieu d'attendre indéfiniment, etPopen.__init__
d'accepter un paramètre de délai d'attente. Une fois que vous avez fait cela, toutes les autresPopen
méthodes (qui appellentwait
) fonctionneront comme prévu, y compriscommunicate
.la source
https://pypi.python.org/pypi/python-subprocess2 fournit des extensions au module de sous-processus qui vous permettent d'attendre jusqu'à un certain laps de temps, sinon de terminer.
Donc, pour attendre jusqu'à 10 secondes que le processus se termine, sinon tuez:
Ceci est compatible avec Windows et Unix. "results" est un dictionnaire, il contient "returnCode" qui est le retour de l'application (ou None si elle devait être supprimée), ainsi que "actionTaken". qui sera "SUBPROCESS2_PROCESS_COMPLETED" si le processus s'est terminé normalement, ou un masque de "SUBPROCESS2_PROCESS_TERMINATED" et SUBPROCESS2_PROCESS_KILLED selon l'action entreprise (voir la documentation pour plus de détails)
la source
pour python 2.6+, utilisez gevent
la source
python 2.7
la source
la source
J'essayais juste d'écrire quelque chose de plus simple.
la source