Gibt es eine pythonische Möglichkeit, nur eine Instanz eines Programms auszuführen?
Die einzige vernünftige Lösung, die ich mir ausgedacht habe, ist der Versuch, sie als Server an einem Port auszuführen. Das zweite Programm, das versucht, an denselben Port zu binden, schlägt fehl. Aber es ist keine wirklich gute Idee, vielleicht gibt es etwas Leichteres als dieses?
(Berücksichtigen Sie, dass das Programm manchmal fehlschlägt, dh Segfault - Dinge wie "Datei sperren" funktionieren also nicht)
python
process
locking
mutual-exclusion
Slava V.
quelle
quelle
Antworten:
Der folgende Code sollte die Aufgabe erfüllen, er ist plattformübergreifend und läuft unter Python 2.4-3.2. Ich habe es unter Windows, OS X und Linux getestet.
Die neueste Codeversion ist singleton.py verfügbar . Bitte melden Sie hier Fehler .
Sie können tend mit einer der folgenden Methoden installieren:
easy_install tendo
pip install tendo
quelle
Einfache
plattformübergreifendeLösung, gefunden in einer anderen Frage von zgoda :Sehr ähnlich wie S.Lotts Vorschlag, aber mit dem Code.
quelle
fcntl
Windows gibt es kein Modul (obwohl die Funktionalität emuliert werden könnte).fg
. Es hört sich also so an, als ob es für Sie richtig funktioniert (dh die App ist noch aktiv, aber angehalten, sodass die Sperre bestehen bleibt).lock_file_pointer = os.open(lock_path, os.O_WRONLY | os.O_CREAT)
Dieser Code ist Linux-spezifisch. Es verwendet 'abstrakte' UNIX-Domänensockets, ist jedoch einfach und hinterlässt keine veralteten Sperrdateien. Ich ziehe es der obigen Lösung vor, da es keinen speziell reservierten TCP-Port erfordert.
Die eindeutige Zeichenfolge
postconnect_gateway_notify_lock
kann geändert werden, um mehrere Programme zuzulassen, für die eine einzelne Instanz erzwungen werden muss.quelle
Ich weiß nicht, ob es pythonisch genug ist, aber in der Java-Welt ist das Abhören eines definierten Ports eine ziemlich weit verbreitete Lösung, da es auf allen wichtigen Plattformen funktioniert und keine Probleme mit abstürzenden Programmen hat.
Ein weiterer Vorteil des Abhörens eines Ports besteht darin, dass Sie einen Befehl an die laufende Instanz senden können. Wenn die Benutzer das Programm beispielsweise ein zweites Mal starten, können Sie der laufenden Instanz einen Befehl senden, um sie anzuweisen, ein anderes Fenster zu öffnen (dies ist beispielsweise bei Firefox der Fall. Ich weiß nicht, ob sie TCP-Ports oder Named Pipes verwenden oder so etwas aber ').
quelle
import socket; s = socket.socket(socket.AF_INET, socket.SOCK_STREAM); s.bind(('localhost', DEFINED_PORT))
. EinOSError
wird ausgelöst, wenn ein anderer Prozess an denselben Port gebunden ist.Noch nie Python geschrieben, aber das habe ich gerade in mycheckpoint implementiert, um zu verhindern, dass es zweimal oder öfter von crond gestartet wird:
Ich habe den Vorschlag von Slava-N gefunden, nachdem ich ihn in einer anderen Ausgabe veröffentlicht habe (http://stackoverflow.com/questions/2959474). Diese Funktion wird als Funktion aufgerufen, sperrt die ausführende Skriptdatei (keine PID-Datei) und behält die Sperre bei, bis das Skript endet (normal oder fehlerhaft).
quelle
Verwenden Sie eine PID-Datei. Sie haben einen bekannten Speicherort, "/ path / to / pidfile", und beim Start machen Sie so etwas (teilweise Pseudocode, weil ich vor dem Kaffee bin und nicht so hart arbeiten möchte):
Mit anderen Worten, Sie überprüfen, ob eine PID-Datei vorhanden ist. Wenn nicht, schreiben Sie Ihre PID in diese Datei. Wenn die PID-Datei vorhanden ist, überprüfen Sie, ob die PID die PID eines laufenden Prozesses ist. Wenn ja, wird ein weiterer Live-Prozess ausgeführt. Fahren Sie einfach herunter. Wenn nicht, ist der vorherige Prozess abgestürzt. Protokollieren Sie ihn und schreiben Sie anstelle der alten Ihre eigene PID in die Datei. Dann fahre fort.
quelle
Sie haben bereits in einem anderen Thread eine Antwort auf eine ähnliche Frage gefunden. Der Vollständigkeit halber lesen Sie, wie Sie dies unter Windows mit dem Namen mutex erreichen können.
http://code.activestate.com/recipes/474070/
quelle
Dies kann funktionieren.
Versuchen Sie, eine PID-Datei an einem bekannten Speicherort zu erstellen. Wenn Sie versagen, hat jemand die Datei gesperrt, Sie sind fertig.
Wenn Sie normal fertig sind, schließen und entfernen Sie die PID-Datei, damit sie von einer anderen Person überschrieben werden kann.
Sie können Ihr Programm in ein Shell-Skript einbinden, das die PID-Datei auch dann entfernt, wenn Ihr Programm abstürzt.
Sie können das Programm auch mit der PID-Datei beenden, wenn es hängt.
quelle
Die Verwendung einer Sperrdatei ist unter Unix ein weit verbreiteter Ansatz. Wenn es abstürzt, müssen Sie manuell bereinigen. Sie können die PID in der Datei speichern und beim Start prüfen, ob ein Prozess mit dieser PID vorliegt. Andernfalls können Sie die Sperrdatei überschreiben. (Sie benötigen jedoch auch eine Sperre für die Datei "read-file-check-pid-rewrite"). Was Sie brauchen, um pid zu bekommen und zu überprüfen, finden Sie im os- Paket. Die übliche Methode, um zu überprüfen, ob ein Prozess mit einer bestimmten PID vorliegt, besteht darin, ihm ein nicht schwerwiegendes Signal zu senden.
Andere Alternativen könnten darin bestehen, dies mit Herden- oder Posix-Semaphoren zu kombinieren.
Das Öffnen eines Netzwerk-Sockets, wie von saua vorgeschlagen, wäre wahrscheinlich das einfachste und portabelste.
quelle
Für jeden, der wxPython für seine Anwendung verwendet, können Sie die Funktion verwenden
wx.SingleInstanceChecker
hier dokumentierte .Ich persönlich benutze eine Unterklasse von der
wx.App
die Verwendung von machtwx.SingleInstanceChecker
und kehrtFalse
aus ,OnInit()
wenn es eine vorhandene Instanz von der App bereits Ausführung wie folgt:Dies ist ein einfacher Drop-In-Ersatz
wx.App
, der mehrere Instanzen verbietet. Um es zu nutzen einfach ersetzenwx.App
mitSingleApp
wie so im Code:quelle
Hier ist meine mögliche Nur-Windows-Lösung. Fügen Sie Folgendes in ein Modul ein, das möglicherweise "onlyone.py" heißt, oder was auch immer. Fügen Sie dieses Modul direkt in Ihre __ main __ Python-Skriptdatei ein.
Erläuterung
Der Code versucht, einen Mutex mit einem Namen zu erstellen, der vom vollständigen Pfad zum Skript abgeleitet ist. Wir verwenden Schrägstriche, um mögliche Verwechslungen mit dem realen Dateisystem zu vermeiden.
Vorteile
quelle
Die beste Lösung hierfür unter Windows ist die Verwendung von Mutexen, wie von @zgoda vorgeschlagen.
Einige Antworten verwenden
fctnl
(auch im @ sorin tendo-Paket enthalten), das unter Windows nicht verfügbar ist, und sollten Sie versuchen, Ihre Python-App mit einem Paket wie einzufrierenpyinstaller
das statische Importe ausführt, wird ein Fehler ausgegeben.Bei Verwendung der Sperrdateimethode tritt außerdem ein
read-only
Problem mit Datenbankdateien auf (dies ist aufgetretensqlite3
).quelle
Ich poste dies als Antwort, da ich ein neuer Benutzer bin und Stack Overflow mich noch nicht abstimmen lässt.
Die Lösung von Sorin Sbarnea funktioniert für mich unter OS X, Linux und Windows, und ich bin dafür dankbar.
Tempfile.gettempdir () verhält sich jedoch unter OS X und Windows auf die eine und unter anderen unter einigen / vielen / allen (?) * Nixen (ohne Berücksichtigung der Tatsache, dass OS X auch Unix ist!). Der Unterschied ist für diesen Code wichtig.
OS X und Windows verfügen über benutzerspezifische temporäre Verzeichnisse, sodass eine von einem Benutzer erstellte temporäre Datei für einen anderen Benutzer nicht sichtbar ist. Im Gegensatz dazu ist unter vielen Versionen von * nix (ich habe Ubuntu 9, RHEL 5, OpenSolaris 2008 und FreeBSD 8 getestet) das temporäre Verzeichnis / tmp für alle Benutzer.
Das heißt, wenn die Sperrdatei auf einem Mehrbenutzercomputer erstellt wird, wird sie in / tmp erstellt, und nur der Benutzer, der die Sperrdatei zum ersten Mal erstellt, kann die Anwendung ausführen.
Eine mögliche Lösung besteht darin, den aktuellen Benutzernamen in den Namen der Sperrdatei einzubetten.
Es ist erwähnenswert, dass sich die OP-Lösung zum Abrufen eines Ports auch auf einem Mehrbenutzercomputer schlecht verhält.
quelle
Ich benutze
single_process
auf meinem Gentoo;Beispiel :
Siehe: https://pypi.python.org/pypi/single_process/1.0
quelle
Ich vermute immer wieder, dass es eine gute POSIXy-Lösung mit Prozessgruppen geben sollte, ohne das Dateisystem treffen zu müssen, aber ich kann es nicht ganz genau sagen. Etwas wie:
Beim Start sendet Ihr Prozess ein 'kill -0' an alle Prozesse in einer bestimmten Gruppe. Wenn solche Prozesse vorhanden sind, wird sie beendet. Dann tritt es der Gruppe bei. Keine anderen Prozesse verwenden diese Gruppe.
Dies hat jedoch eine Rennbedingung - mehrere Prozesse können dies genau zur gleichen Zeit tun und alle schließen sich der Gruppe an und laufen gleichzeitig. Wenn Sie eine Art Mutex hinzugefügt haben, um die Wasserdichtigkeit zu gewährleisten, benötigen Sie die Prozessgruppen nicht mehr.
Dies mag akzeptabel sein, wenn Ihr Prozess nur einmal pro Minute oder jede Stunde von cron gestartet wird, aber es macht mich ein bisschen nervös, dass es genau an dem Tag schief gehen würde, an dem Sie es nicht wollen.
Ich denke, das ist doch keine sehr gute Lösung, es sei denn, jemand kann sie verbessern?
quelle
Ich bin letzte Woche genau auf dieses Problem gestoßen, und obwohl ich einige gute Lösungen gefunden habe, habe ich beschlossen, ein sehr einfaches und sauberes Python-Paket zu erstellen und es auf PyPI hochzuladen. Es unterscheidet sich von tendo dadurch, dass es jeden String-Ressourcennamen sperren kann. Obwohl Sie sicherlich sperren könnten
__file__
, um den gleichen Effekt zu erzielen.Installieren mit:
pip install quicklock
Die Verwendung ist sehr einfach:
Schauen Sie sich das an: https://pypi.python.org/pypi/quicklock
quelle
Aufbauend auf der Antwort von Roberto Rosario habe ich folgende Funktion:
Wir müssen global
SOCKET
vaiable definieren, da es nur dann Müll wird, wenn der gesamte Prozess beendet wird. Wenn wir eine lokale Variable in der Funktion deklarieren, wird sie nach dem Beenden der Funktion nicht mehr gültig sein, sodass der Socket gelöscht wird.Der gesamte Kredit sollte an Roberto Rosario gehen, da ich nur seinen Code klarstelle und ausarbeite. Und dieser Code funktioniert nur unter Linux, wie der folgende zitierte Text von https://troydhanson.github.io/network/Unix_domain_sockets.html erklärt:
quelle
Linux Beispiel
Diese Methode basiert auf der Erstellung einer temporären Datei, die nach dem Schließen der Anwendung automatisch gelöscht wird. Beim Programmstart überprüfen wir das Vorhandensein der Datei. Wenn die Datei vorhanden ist (eine Ausführung steht noch aus), wird das Programm geschlossen. Andernfalls wird die Datei erstellt und die Ausführung des Programms fortgesetzt.
quelle
Auf einem Linux-System könnte man auch
pgrep -a
nach der Anzahl der Instanzen fragen , das Skript befindet sich in der Prozessliste (Option -a zeigt die vollständige Befehlszeilenzeichenfolge an). Z.BEntfernen Sie,
-u $UID
wenn die Einschränkung für alle Benutzer gelten soll. Haftungsausschluss: a) Es wird davon ausgegangen, dass der (Basis-) Name des Skripts eindeutig ist. B) Es können Rennbedingungen vorliegen.quelle
quelle