Im Moment habe ich ein zentrales Modul in einem Framework, das mit dem Python 2.6- multiprocessing
Modul mehrere Prozesse erzeugt . Da es verwendet wird multiprocessing
, gibt es ein Multiprozessor-fähiges Protokoll auf Modulebene LOG = multiprocessing.get_logger()
. Gemäß den Dokumenten verfügt dieser Logger über prozessfreigabene Sperren, damit Sie nicht die Dinge sys.stderr
(oder was auch immer für ein Dateihandle) beschädigen, indem mehrere Prozesse gleichzeitig darauf schreiben.
Das Problem, das ich jetzt habe, ist, dass die anderen Module im Framework nicht multiprocessing-fähig sind. So wie ich es sehe, muss ich dafür sorgen, dass alle Abhängigkeiten von diesem zentralen Modul eine multiprozessorientierte Protokollierung verwenden. Das ist innerhalb des Frameworks ärgerlich , geschweige denn für alle Clients des Frameworks. Gibt es Alternativen, an die ich nicht denke?
quelle
multiprocessing.get_logger()
? Es scheint, dass auf diesen anderen Arten der Protokollierung die Protokollierungsfunktionalitätmultiprocessing
von geringem Wert ist.get_logger()
ist der vommultiprocessing
Modul selbst verwendete Logger . Dies ist nützlich, wenn Sie einmultiprocessing
Problem beheben möchten .Antworten:
Der einzige Weg, um nicht aufdringlich damit umzugehen, ist:
select
anhand der Dateideskriptoren der Pipes eine Zusammenführungssortierung für die verfügbaren Protokolleinträge durch und leeren Sie sie in das zentralisierte Protokoll. Wiederholen Sie diesen Vorgang.)quelle
atexit
:-). Das Problem ist, dass Sie keine Echtzeitanzeige erhalten. Dies kann Teil des Preises für Multiprocessing im Gegensatz zu Multithreading sein.multiprocessing.Queue
wird nicht einfacher, wenn viel Code neu verdrahtet werdenmultiprocessing.Queue
muss und / oder wenn die Leistung ein Problem darstelltIch habe gerade einen eigenen Log-Handler geschrieben, der einfach alles über eine Pipe an den übergeordneten Prozess weiterleitet. Ich habe es nur zehn Minuten lang getestet, aber es scheint ziemlich gut zu funktionieren.
( Hinweis: Dies ist fest codiert
RotatingFileHandler
, was mein eigener Anwendungsfall ist.)Update: @javier behält diesen Ansatz jetzt als Paket bei, das auf Pypi verfügbar ist - siehe Multiprocessing-Logging auf Pypi, github unter https://github.com/jruere/multiprocessing-logging
Update: Implementierung!
Dies verwendet jetzt eine Warteschlange für die korrekte Behandlung der Parallelität und stellt auch Fehler korrekt wieder her. Ich benutze dies jetzt seit mehreren Monaten in der Produktion und die aktuelle Version unten funktioniert ohne Probleme.
quelle
multiprocessing.Queue
ein Thread verwendet wird, um input()
. Rufen Sie also nicht aufput
(dh protokollieren Sie eine Nachricht mit demMultiProcessingLog
Handler), bevor Sie alle Unterprozesse erstellt haben. Andernfalls ist der Thread im untergeordneten Prozess tot. Eine Lösung besteht darin,Queue._after_fork()
zu Beginn jedes untergeordneten Prozesses aufzurufen odermultiprocessing.queues.SimpleQueue
stattdessen zu verwenden , was keinen Thread beinhaltet, sondern blockiert.multiprocessing-logging
.QueueHandler
ist in Python 3.2+ nativ und macht genau das. Es ist in früheren Versionen leicht zu replizieren.Python-Dokumente enthalten zwei vollständige Beispiele: Protokollierung in einer einzelnen Datei aus mehreren Prozessen
Wenn Sie Python <3.2 verwenden, kopieren
QueueHandler
Sie einfach Ihren eigenen Code von: https://gist.github.com/vsajip/591589 oder importieren Sie alternativ logutils .Jeder Prozess (einschließlich des übergeordneten Prozesses) legt seine Protokollierung auf dem ab
Queue
, und dann nimmt einlistener
Thread oder Prozess (für jeden wird ein Beispiel bereitgestellt) diese auf und schreibt sie alle in eine Datei - ohne das Risiko von Beschädigung oder Verstümmelung.quelle
Im Folgenden finden Sie eine weitere Lösung mit dem Schwerpunkt auf Einfachheit für alle anderen (wie mich), die von Google hierher kommen. Die Protokollierung sollte einfach sein! Nur für 3.2 oder höher.
quelle
QueueHandler
undQueueListener
können auch in Python 2.7 verwendet werden, das imlogutils
Paket verfügbar ist .Eine weitere Alternative könnten die verschiedenen nicht dateibasierten Protokollierungshandler im
logging
Paket sein :SocketHandler
DatagramHandler
SyslogHandler
(und andere)
Auf diese Weise könnten Sie leicht irgendwo einen Protokollierungsdämon haben, in den Sie sicher schreiben und die Ergebnisse korrekt verarbeiten können. (ZB ein einfacher Socket-Server, der die Nachricht einfach abhebt und an seinen eigenen rotierenden Datei-Handler ausgibt.)
Das
SyslogHandler
würde sich auch für Sie erledigen. Natürlich können Sie auch Ihre eigene Instanz verwendensyslog
, nicht die des Systems.quelle
Eine Variante der anderen, die den Protokollierungs- und Warteschlangenthread getrennt hält.
quelle
fileConfig()
in MainProcess und eines kaum konfigurierten Loggers in PoolWorkers (nur mitsetLevel(logging.NOTSET)
). Wie ich in einem anderen Kommentar erwähnt habe, verwende ich Pool, sodass ich meine Warteschlange (Proxy) vom Manager beziehen musste, anstatt sie zu verarbeiten, damit sie eingelegt werden kann. Auf diese Weise kann ich die Warteschlange an einen Mitarbeiter innerhalb eines Wörterbuchs übergeben (von dem der größte Teil von argsparse object using abgeleitet istvars()
). Ich denke, am Ende ist dies der beste Ansatz für MS Windows, dem fork () fehlt und die @ zzzeak-Lösung kaputt geht.fork
. Auf diese Weise hat jeder Prozess seine eigene unabhängige nutzlose Warteschlange. Der zweite Ansatz in der verknüpften Frage / Antwort funktioniert auf solchen Plattformen nicht. Dies ist ein Weg zu nicht portierbarem Code.multiprocessing.Queue
mit dem Hauptprozess teilen , und seitdem benutze ich ihn ständig. Ich werde nicht behaupten zu verstehen, warum es funktioniert.Alle aktuellen Lösungen sind mithilfe eines Handlers zu stark an die Protokollierungskonfiguration gekoppelt. Meine Lösung hat die folgende Architektur und Funktionen:
multiprocessing.Queue
logging.Logger
(und bereits definierte Instanzen) gepatcht, um alle Datensätze an die Warteschlange zu sendenCode mit Verwendungsbeispiel und Ausgabe finden Sie in der folgenden Liste: https://gist.github.com/schlamar/7003737
quelle
daemon_thread.daemon
zuTrue
. Ich musste dies tun, damit mein Python-Programm ordnungsgemäß beendet wird, wenn im Kontextmanager eine Ausnahme auftritt.func
inlogged_call
, andernfalls wird die Ausnahme wäre mit anderen protokollierten Ausgabe verstümmelt bekommen. Hier ist meine modifizierte Version davon: gist.github.com/blah238/8ab79c4fe9cdb254f5c37abfc5dc85bfDa wir die Multiprozessprotokollierung für so viele Publisher und einen Abonnenten (Listener) darstellen können, ist die Verwendung von ZeroMQ zur Implementierung von PUB-SUB-Messaging in der Tat eine Option.
Darüber hinaus implementiert das PyZMQ- Modul, die Python-Bindungen für ZMQ, PUBHandler , ein Objekt zum Veröffentlichen von Protokollierungsnachrichten über einen zmq.PUB-Socket.
Im Web gibt es eine Lösung für die zentralisierte Protokollierung von verteilten Anwendungen mit PyZMQ und PUBHandler, die problemlos für die lokale Arbeit mit mehreren Veröffentlichungsprozessen verwendet werden kann.
quelle
Ich mag auch die Antwort von zzzeek, aber Andre hat Recht, dass eine Warteschlange erforderlich ist, um ein Verstümmeln zu verhindern. Ich hatte etwas Glück mit der Pfeife, sah aber ein Gurgeln, was etwas zu erwarten ist. Die Implementierung erwies sich als schwieriger als ich dachte, insbesondere aufgrund der Ausführung unter Windows, wo es einige zusätzliche Einschränkungen für globale Variablen und andere Dinge gibt (siehe: Wie wird Python Multiprocessing unter Windows implementiert? ).
Aber ich habe es endlich geschafft. Dieses Beispiel ist wahrscheinlich nicht perfekt, daher sind Kommentare und Vorschläge willkommen. Es wird auch nicht unterstützt, den Formatierer oder etwas anderes als den Root-Logger festzulegen. Grundsätzlich müssen Sie den Logger in jedem der Poolprozesse mit der Warteschlange neu starten und die anderen Attribute im Logger einrichten.
Auch hier sind Vorschläge zur Verbesserung des Codes willkommen. Ich kenne noch nicht alle Python-Tricks :-)
quelle
if 'MainProcess' == multiprocessing.current_process().name:
anstelle des Passierens verwendet werden kannchild
?Veröffentlichen Sie einfach irgendwo Ihre Instanz des Loggers. Auf diese Weise können die anderen Module und Clients Ihre API verwenden, um den Logger abzurufen, ohne dies zu müssen
import multiprocessing
.quelle
import logging; logging.basicConfig(level=logging.DEBUG); logging.debug('spam!')
von überall aus in der Lage zu sein und es richtig funktionieren zu lassen.Ich mochte die Antwort von zzzeek. Ich würde nur die Pipe durch eine Warteschlange ersetzen, da mehrere Threads / Prozesse, die dasselbe Pipe-Ende zum Generieren von Protokollnachrichten verwenden, verstümmelt werden.
quelle
Wie wäre es, wenn Sie die gesamte Protokollierung an einen anderen Prozess delegieren, der alle Protokolleinträge aus einer Warteschlange liest?
Teilen Sie einfach LOG_QUEUE über einen der Multiprozessmechanismen oder sogar über die Vererbung, und alles funktioniert einwandfrei!
quelle
Ich habe eine ähnliche Lösung wie Ironhacker, außer dass ich logging.exception in einem Teil meines Codes verwende und festgestellt habe, dass ich die Ausnahme formatieren musste, bevor ich sie über die Warteschlange zurückgeben konnte, da Tracebacks nicht pickle'able sind:
quelle
Unten finden Sie eine Klasse, die in einer Windows-Umgebung verwendet werden kann und ActivePython erfordert. Sie können auch für andere Protokollierungshandler (StreamHandler usw.) erben.
Und hier ist ein Beispiel, das die Verwendung demonstriert:
quelle
multiprocessing.Lock()
anstelle von Windows Mutex die Lösung portabel machen.Hier ist mein einfacher Hack / Workaround ... nicht der umfassendste, aber leicht zu ändernde und einfacher zu lesen und zu verstehen, denke ich als alle anderen Antworten, die ich vor dem Schreiben gefunden habe:
quelle
Es gibt dieses tolle Paket
Paket: https://pypi.python.org/pypi/multiprocessing-logging/
Code: https://github.com/jruere/multiprocessing-logging
Installieren:
Dann füge hinzu:
quelle
Eine der Alternativen besteht darin, die Mehrfachverarbeitungsprotokollierung in eine bekannte Datei zu schreiben und einen
atexit
Handler zu registrieren , der an diesen Prozessen teilnimmt. Lesen Sie ihn auf stderr zurück. Auf diese Weise erhalten Sie jedoch keinen Echtzeitfluss zu den Ausgabemeldungen auf stderr.quelle
Wenn in einer Kombination von Sperren, Threads und Gabeln im
logging
Modul Deadlocks auftreten , wird dies im Fehlerbericht 6721 gemeldet (siehe auch verwandte SO-Frage ).Es gibt eine kleine Fixup Lösung gepostet hier .
Dadurch werden jedoch nur mögliche Deadlocks behoben
logging
. Das wird nicht beheben, dass die Dinge vielleicht verstümmelt sind. Siehe die anderen Antworten hier.quelle
Einfachste Idee wie erwähnt:
[WatchedFileHandler][1]
. Die Gründe für diesen Handler werden hier ausführlich besprochen , aber kurz gesagt, es gibt bestimmte schlechtere Rennbedingungen mit den anderen Logging-Handlern. Dieser hat das kürzeste Fenster für die Rennbedingung.quelle
Für alle, die dies benötigen, habe ich einen Decorator für das Paket multiprocessing_logging geschrieben, der den aktuellen Prozessnamen zu den Protokollen hinzufügt, damit klar wird, wer was protokolliert.
Außerdem wird install_mp_handler () ausgeführt, sodass es nicht mehr sinnvoll ist, es vor dem Erstellen eines Pools auszuführen.
Auf diese Weise kann ich sehen, welcher Mitarbeiter welche Protokollnachrichten erstellt.
Hier ist die Blaupause mit einem Beispiel:
quelle
Ich überlasse diese Antwort meinen Kindern, die seit Jahrzehnten das gleiche Problem haben und diese Frage auf dieser Website gefunden haben.
Einfachheit gegen Überkomplikation. Verwenden Sie einfach andere Werkzeuge. Python ist fantastisch, aber es wurde nicht entwickelt, um einige Dinge zu tun.
Das folgende Snippet für den logrotate Daemon funktioniert für mich und macht die Dinge nicht zu kompliziert . Planen Sie es stündlich und
So installiere ich es (Symlinks funktionieren nicht für logrotate):
quelle