Existe-t-il un moyen pythonique d'avoir une seule instance d'un programme en cours d'exécution?
La seule solution raisonnable que j'ai trouvée est d'essayer de l'exécuter en tant que serveur sur un port, puis le deuxième programme essayant de se lier au même port - échoue. Mais ce n'est pas vraiment une bonne idée, peut-être qu'il y a quelque chose de plus léger que ça?
(Tenez compte du fait que le programme devrait parfois échouer, c'est-à-dire segfault - donc des choses comme "verrouiller le fichier" ne fonctionneront pas)
python
process
locking
mutual-exclusion
Slava V
la source
la source
Réponses:
Le code suivant devrait faire le travail, il est multiplateforme et fonctionne sur Python 2.4-3.2. Je l'ai testé sous Windows, OS X et Linux.
La dernière version du code est disponible singleton.py . Veuillez signaler les bogues ici .
Vous pouvez installer tend en utilisant l'une des méthodes suivantes:
easy_install tendo
pip install tendo
la source
Facile,
Solutionmultiplateforme, trouvée dans une autre question de zgoda :Un peu comme la suggestion de S.Lott, mais avec le code.
la source
fcntl
module sous Windows (bien que la fonctionnalité puisse être émulée).fg
. Donc, il semble que cela fonctionne correctement pour vous (c'est-à-dire que l'application est toujours active, mais suspendue, de sorte que le verrou reste en place).lock_file_pointer = os.open(lock_path, os.O_WRONLY | os.O_CREAT)
Ce code est spécifique à Linux. Il utilise des sockets de domaine UNIX «abstraits», mais c'est simple et ne laissera pas de fichiers de verrouillage périmés. Je le préfère à la solution ci-dessus car il ne nécessite pas de port TCP spécialement réservé.
La chaîne unique
postconnect_gateway_notify_lock
peut être modifiée pour autoriser plusieurs programmes qui nécessitent une seule instance appliquée.la source
Je ne sais pas si c'est assez pythonique, mais dans le monde Java, écouter sur un port défini est une solution assez largement utilisée, car elle fonctionne sur toutes les principales plates-formes et n'a aucun problème avec les programmes qui plantent.
Un autre avantage d'écouter un port est que vous pouvez envoyer une commande à l'instance en cours d'exécution. Par exemple, lorsque les utilisateurs démarrent le programme une deuxième fois, vous pouvez envoyer à l'instance en cours d'exécution une commande pour lui dire d'ouvrir une autre fenêtre (c'est ce que fait Firefox, par exemple. Je ne sais pas s'ils utilisent des ports TCP ou des tubes nommés ou quelque chose comme ça, 'cependant).
la source
import socket; s = socket.socket(socket.AF_INET, socket.SOCK_STREAM); s.bind(('localhost', DEFINED_PORT))
. UnOSError
sera déclenché si un autre processus est lié au même port.Jamais écrit python auparavant, mais c'est ce que je viens d'implémenter dans mycheckpoint, pour éviter qu'il ne soit démarré deux fois ou plus par crond:
J'ai trouvé la suggestion de Slava-N après l'avoir publiée dans un autre numéro (http://stackoverflow.com/questions/2959474). Celui-ci est appelé en tant que fonction, verrouille le fichier de scripts en cours d'exécution (pas un fichier pid) et maintient le verrou jusqu'à la fin du script (normal ou erreur).
la source
Utilisez un fichier pid. Vous avez un emplacement connu, "/ chemin / vers / pidfile" et au démarrage vous faites quelque chose comme ça (partiellement pseudocode parce que je suis en pré-café et que je ne veux pas travailler si dur):
Donc, en d'autres termes, vous vérifiez si un pidfile existe; sinon, écrivez votre pid dans ce fichier. Si le pidfile existe, vérifiez si le pid est le pid d'un processus en cours d'exécution; si c'est le cas, alors vous avez un autre processus en direct en cours d'exécution, alors arrêtez simplement. Sinon, le processus précédent s'est écrasé, alors enregistrez-le, puis écrivez votre propre pid dans le fichier à la place de l'ancien. Alors continuez.
la source
Vous avez déjà trouvé une réponse à une question similaire dans un autre fil, donc par souci d'exhaustivité, voyez comment obtenir la même chose sur Windows uning nommé mutex.
http://code.activestate.com/recipes/474070/
la source
Cela peut fonctionner.
Essayez de créer un fichier PID vers un emplacement connu. Si vous échouez, quelqu'un a verrouillé le fichier, vous avez terminé.
Lorsque vous avez terminé normalement, fermez et supprimez le fichier PID afin que quelqu'un d'autre puisse l'écraser.
Vous pouvez envelopper votre programme dans un script shell qui supprime le fichier PID même si votre programme plante.
Vous pouvez également utiliser le fichier PID pour tuer le programme s'il se bloque.
la source
L'utilisation d'un fichier de verrouillage est une approche assez courante sous unix. En cas de panne, vous devez nettoyer manuellement. Vous pouvez stocker le PID dans le fichier et, au démarrage, vérifier s'il existe un processus avec ce PID, en remplaçant le fichier de verrouillage dans le cas contraire. (Cependant, vous avez également besoin d'un verrou autour du fichier read-file-check-pid-rewrite-file). Vous trouverez ce dont vous avez besoin pour obtenir et vérifier pid dans l' os paquet . La manière courante de vérifier s'il existe un processus avec un pid donné est de lui envoyer un signal non fatal.
D'autres alternatives pourraient être de combiner cela avec des sémaphores flock ou posix.
Ouvrir une prise réseau, comme le proposait saua, serait probablement la plus simple et la plus portable.
la source
Pour toute personne utilisant wxPython pour son application, vous pouvez utiliser la fonction
wx.SingleInstanceChecker
documentée ici .Personnellement , j'utiliser une sous - classe
wx.App
qui utilisewx.SingleInstanceChecker
et revientFalse
deOnInit()
s'il y a une instance existante de l'application exécutant déjà comme ceci:Il s'agit d'un simple remplacement instantané
wx.App
qui interdit plusieurs instances. Pour l'utiliser, remplacez-le simplementwx.App
parSingleApp
dans votre code comme ceci:la source
Voici mon éventuelle solution Windows uniquement. Mettez ce qui suit dans un module, peut-être appelé «onlyone.py», ou autre. Incluez ce module directement dans votre __ fichier de script python __ main __.
Explication
Le code tente de créer un mutex avec un nom dérivé du chemin d'accès complet au script. Nous utilisons des barres obliques pour éviter toute confusion potentielle avec le système de fichiers réel.
Avantages
la source
La meilleure solution pour cela sur Windows est d'utiliser des mutex comme suggéré par @zgoda.
Certaines réponses utilisent
fctnl
(inclus également dans le package @sorin tendo) qui n'est pas disponible sur Windows et si vous essayez de geler votre application python en utilisant un package comme celuipyinstaller
qui effectue des importations statiques, cela génère une erreur.En outre, l'utilisation de la méthode de fichier de verrouillage crée un
read-only
problème avec les fichiers de base de données (rencontré avecsqlite3
).la source
Je publie ceci comme réponse car je suis un nouvel utilisateur et Stack Overflow ne me permettra pas encore de voter.
La solution de Sorin Sbarnea fonctionne pour moi sous OS X, Linux et Windows, et j'en suis reconnaissant.
Cependant, tempfile.gettempdir () se comporte d'une manière sous OS X et Windows et d'une autre sous certains / plusieurs / tous (?) * Nixes (en ignorant le fait qu'OS X est aussi Unix!). La différence est importante pour ce code.
OS X et Windows ont des répertoires temporaires spécifiques à l'utilisateur, donc un fichier temporaire créé par un utilisateur n'est pas visible pour un autre utilisateur. En revanche, sous de nombreuses versions de * nix (j'ai testé Ubuntu 9, RHEL 5, OpenSolaris 2008 et FreeBSD 8), le répertoire temporaire est / tmp pour tous les utilisateurs.
Cela signifie que lorsque le fichier de verrouillage est créé sur une machine multi-utilisateurs, il est créé dans / tmp et que seul l'utilisateur qui crée le fichier de verrouillage la première fois pourra exécuter l'application.
Une solution possible consiste à intégrer le nom d'utilisateur actuel dans le nom du fichier de verrouillage.
Il convient de noter que la solution de l'OP consistant à saisir un port se comportera également mal sur une machine multi-utilisateur.
la source
J'utilise
single_process
sur mon gentoo;exemple :
reportez-vous à: https://pypi.python.org/pypi/single_process/1.0
la source
Je soupçonne toujours qu'il devrait y avoir une bonne solution POSIXy utilisant des groupes de processus, sans avoir à frapper le système de fichiers, mais je ne peux pas tout à fait clouer. Quelque chose comme:
Au démarrage, votre processus envoie un «kill -0» à tous les processus d'un groupe particulier. Si de tels processus existent, il s'arrête. Puis il rejoint le groupe. Aucun autre processus n'utilise ce groupe.
Cependant, cela a une condition de concurrence - plusieurs processus pourraient tous faire cela exactement en même temps et tous finiraient par rejoindre le groupe et fonctionner simultanément. Au moment où vous avez ajouté une sorte de mutex pour le rendre étanche, vous n'avez plus besoin des groupes de processus.
Cela pourrait être acceptable si votre processus ne démarre que par cron, une fois par minute ou toutes les heures, mais cela me rend un peu nerveux à l'idée que cela se passe mal précisément le jour où vous ne le souhaitez pas.
Je suppose que ce n'est pas une très bonne solution après tout, à moins que quelqu'un ne puisse l'améliorer?
la source
J'ai rencontré ce problème exact la semaine dernière, et bien que j'aie trouvé de bonnes solutions, j'ai décidé de créer un package python très simple et propre et de le télécharger sur PyPI. Il diffère de tendo en ce qu'il peut verrouiller n'importe quel nom de ressource de chaîne. Bien que vous puissiez certainement verrouiller
__file__
pour obtenir le même effet.Installer avec:
pip install quicklock
Son utilisation est extrêmement simple:
Jetez un œil: https://pypi.python.org/pypi/quicklock
la source
En me basant sur la réponse de Roberto Rosario, je propose la fonction suivante:
Nous devons définir la
SOCKET
variable globale car elle ne sera récupérée que lorsque l'ensemble du processus se fermera. Si nous déclarons une variable locale dans la fonction, elle sortira de la portée après la sortie de la fonction, donc le socket sera supprimé.Tout le mérite revient à Roberto Rosario, puisque je ne fais que clarifier et développer son code. Et ce code ne fonctionnera que sous Linux, comme l' explique le texte cité suivant de https://troydhanson.github.io/network/Unix_domain_sockets.html :
la source
exemple Linux
Cette méthode repose sur la création d'un fichier temporaire supprimé automatiquement après la fermeture de l'application. le lancement du programme nous vérifions l'existence du fichier; si le fichier existe (il y a une exécution en attente), le programme est fermé; sinon, il crée le fichier et poursuit l'exécution du programme.
la source
Sur un système Linux, on peut également demander
pgrep -a
le nombre d'instances, le script se trouve dans la liste des processus (l'option -a révèle la chaîne complète de la ligne de commande). Par exempleSupprimer
-u $UID
si la restriction doit s'appliquer à tous les utilisateurs. Avertissement: a) il est supposé que le nom (de base) du script est unique, b) il peut y avoir des conditions de concurrence.la source
la source