7
votes

Python Subprocess Express des descripteurs de fichiers

J'ai un projet Python à long terme qui utilise le module de sous-processus pour démarrer divers autres programmes. Il attend que chaque programme finit, puis termine la fonction wrapper et retourne à sa boucle d'attente.

Finalement, cela apporte l'ordinateur qu'il fonctionne sur une halte de meulage, avec l'erreur qu'il n'y a plus de descripteurs de fichiers disponibles.

Je ne suis pas capable de trouver nulle part dans le Subprocess Documents Qu'advient-il de déposer des descripteurs lorsqu'un processus d'enfant se ferme. Au début, je pensais qu'ils se fermeraient automatiquement, car la commande subtrocess.call () attend jusqu'à ce que l'enfant se termine.

Mais si c'était le cas, je n'aurais pas de problème. J'ai également pensé que s'il restait quelque chose de plus, Python détruirait-le lorsque la fonction se termine et que les descripteurs de fichiers sont hors de portée. Mais cela ne semble pas être le cas non plus.

Comment aurais-je accès à ces descripteurs de fichiers? La fonction SubProcess.Call () ne renvoie que le code de sortie et non des descripteurs de fichiers ouverts. Y a-t-il autre chose qui me manque ici?

Ce projet agit comme une colle entre diverses applications d'entreprise. Lesdites applications ne peuvent pas être pipelines et elles sont des systèmes d'interface graphique. Donc, la seule chose que je puisse faire est de les démarrer avec leurs macros intégrées. Ces fichiers texte de sortie de macros, que j'utilise pour le programme suivant dans le tuyau.

Oui, c'est aussi mauvais que ça sonne. Heureusement, tous les fichiers finissent par avoir de jolis noms uniques. Donc, ici dans les prochains jours, j'utiliserai l'outil SYS Internals suggéré ci-dessous pour essayer de suivre le fichier. Je vous ferai savoir comment il s'avère.

La plupart des fichiers que je n'ouvre pas, je viens de les déplacer avec la fonction win32file.copyfyfile ().


2 commentaires

Peut-être que vous exécutez un processus qui ouvre un autre processus? Ensuite, lorsque votre processus a pris fin, vous pensez que vous êtes nettoyé, mais en fait pas vraiment? Avez-vous vérifié PS / Top / Task Manager pour voir si vous avez des processus en cours d'exécution?


Est-ce que ce "projet Python qui utilise le module de sous-processus pour démarrer divers autres programmes" de construire des pipelines ou rediriger STDIN ou STDOUT pour les sous-processus? Si oui, vous devez résumer ce qui se passe dans ce module.


4 Réponses :


0
votes

Les descripteurs de fichiers disparaissent lorsque le processus le fait, il doit donc s'agir de la maintien des descripteurs de fichiers (vous pouvez vérifier cela avec lsof ). Que fait le code dans le parent?


2 commentaires

Le projet est «colle» entre divers programmes externes différents. Il regarde un répertoire pour un nouveau fichier et lancé chacun des processus externes de la séquence. Pour les faire jouer sympa, il doit déplacer des fichiers après que chacun est terminé. Malheureusement, il doit vivre sur la machine Windows, donc je n'ai pas de lsof.


Sous Windows, Sysinternals Le moniteur de processus fera la même chose. Malheureusement, ni l'un ni l'autre ne vous aidera à identifier où dans Python les fichiers sont ouverts.



2
votes

Quelle version Python utilisez-vous? Il y a une fuite connue de descripteurs de fichiers avec sous-processus.Popen () qui pourrait également affecter les sous-processus.call ()

http://bugs.python.org/issue6274

Comme vous pouvez le constater, cela n'a été fixé que dans Python-2.6


1 commentaires

J'utilise actuellement 2,7, donc je ne pense pas que ce soit un problème. Bien que si c'était arrivé une fois, cela pourrait se reproduire ...



1
votes

Le problème est parti après une refactorisation majeure, je vais donc noter ici que la partie du problème que j'ai couru était à la recherche d'outils de débogage de mémoire pour Python.

J'ai depuis trouvé tasse .


3 commentaires

J'ai eu le même problème que vous avez eu sur cette question. J'ai également une longue sous-processus de script Python. Et maintenant, je suis hors descripteur de dossier, pourriez-vous me dire plus sur la manière dont votre refactoring majeur faire le problème est parti? Je vous remercie


@Hvnsweeting j'ai cassé la base de code dans des objets individuels avec des rôles bien définis. Seul un objet était responsable du sous-processus en cours d'exécution et il a été créé et détruit par un ancien objet de course à pied qui n'a ouvert aucun fichier lui-même. De cette façon, lorsque l'objet de traitement était terminé, la détruire de manière proprement la chaîne de référence, et le collecteur des ordures pouvait nettoyer.


J'ai corrigé mon problème et j'ai compris qu'il n'est pas relatif à la sous-processus. C'est ma faute de fermeture de fermeture lorsque l'erreur se produit. Merci de votre aide.



5
votes

J'ai eu le même problème.

Nous utilisons constamment des sous-processus.Popen () pour invoquer des outils externes dans un environnement Windows. À un moment donné, nous avons eu un problème dans lequel aucun autre descripteurs de fichiers n'était disponible. Nous avons foré à la question et avons découvert que les instances de sous-processus.Popen se comportent différemment sous Windows que sous Linux. P>

Si l'instance popen n'est pas détruite (par exemple, en gardant une référence en quelque sorte, et ne permettant ainsi pas à la poubelle. Pour détruire l'objet), les tuyaux créés lors de l'appel restent ouverts sous Windows, tandis que sous Linux, ils ont été automatiquement fermés après que popen.communicate () a été appelée. Si cela est poursuivi dans d'autres appels, les descripteurs de fichiers «zombies» des tuyaux s'empileront et provoqueront éventuellement une exception Python ioerror: [errno 24] trop de fichiers ouverts code>. P> Comment obtenir des descripteurs de fichier ouverts dans Python h2>

Pour que nous puissions résoudre nos problèmes, nous avions besoin d'un moyen d'obtenir les descripteurs de fichiers valides dans un script Python. Donc, nous avons conçu le script suivant. Notez que nous ne vérifions que des descripteurs de fichiers de 0 à 100, puisque nous n'ouvrons pas tant de fichiers simultanément. P>

fd_table_status.py strong>: p> xxx Pré>

Lorsque vous exécutez simplement, il affichera tous les descripteurs de fichiers ouverts et leur type respectif: p> xxx pré>

La sortie est la même en appelant fd_table_status_str () via le code PYTHON. Pour plus de détails sur la «Chr» et le respect de «codes courts» signification, voir Documentation Python sur Stat . p>

Comportement de descripteur de fichier de test h2>

Essayez d'exécuter le script suivant sous Linux et Windows: p>

Test_fd_handling.py strong> : P>

1) Initial file descriptors:
Open file handles: 0: CHR, 1: CHR, 2: CHR
2) After file open, before Popen:
Open file handles: 0: CHR, 1: CHR, 2: CHR, 3: REG
3) After Popen, before reading piped output:
Open file handles: 0: CHR, 1: CHR, 2: CHR, 3: REG, 4: FIFO, 5: FIFO, 6: FIFO
4) After Popen.communicate():
Open file handles: 0: CHR, 1: CHR, 2: CHR, 3: REG, 5: FIFO, 6: FIFO
5) After deleting reference to Popen instance:
Open file handles: 0: CHR, 1: CHR, 2: CHR, 3: REG
6) After deleting reference to file instance:
Open file handles: 0: CHR, 1: CHR, 2: CHR
7) child process had the following file descriptors:
Open file handles: 0: FIFO, 1: FIFO, 2: FIFO


2 commentaires

merveilleuse réponse! Cela expliquerait pourquoi mon refactoring fixe le problème, car les instances popen sont complètement détruites. J'avais déjà supposé que lorsqu'il est tombé hors de portée, le GC les obtiendrait, mais le tuyau ouvert le gardait probablement autour.


Très probablement, il y avait une référence persistante à l'instance popen dans votre code quelque part, ce qui n'a pas laissé le GC le détruire. Ce problème est étroitement lié au problème global de héritage descripteur de fichiers. Regardez une autre "creuse" que j'ai faite sur Descripteurs de fichiers hérités à Python .