Ich habe einen langwierigen Prozess, der viele Dinge in eine Datei schreibt. Das Ergebnis sollte alles oder nichts sein, also schreibe ich in eine temporäre Datei und benenne sie am Ende in den richtigen Namen um. Momentan ist mein Code wie folgt:
%Vor%Ich bin aus mehreren Gründen nicht glücklich damit:
Irgendwelche Vorschläge, wie ich meinen Code verbessern kann? Gibt es eine Bibliothek, die mir helfen kann?
Sie können Pythons tempfile
Modul verwenden, um Ihnen einen temporären Dateinamen zu geben. Es kann eine temporäre Datei in einer Thread-sicheren Weise erstellen, anstatt eine mit time.time()
zu erstellen, die denselben Namen zurückgeben kann, wenn sie in mehreren Threads gleichzeitig verwendet wird.
Wie in einem Kommentar zu Ihrer Frage vorgeschlagen, kann dies mit der Verwendung eines Kontextmanagers gekoppelt werden. Sie können einige Ideen zur Implementierung von dem, was Sie tun möchten, indem Sie sich Python tempfile.py
Quellen ansehen.
Das folgende Code-Snippet kann tun, was Sie wollen. Es verwendet einige der Interna der Objekte, die von tempfile
zurückgegeben werden.
os.path.exists()
und os.rename()
, der eine Race-Bedingung verursachen könnte. Für eine atomare Umbenennung unter Linux müssen die Quelle und die Ziele auf demselben Dateisystem liegen, weshalb dieser Code die temporäre Datei im selben Verzeichnis wie die Zieldatei ablegt. RenamedTemporaryFile
-Klasse sollte sich für die meisten Zwecke wie ein NamedTemporaryFile
verhalten, außer wenn sie mit dem Kontextmanager geschlossen wird, wird die Datei umbenannt. Beispiel:
%Vor%Sie können es dann wie folgt verwenden:
%Vor%Beim Schreiben geht der Inhalt in eine temporäre Datei, beim Beenden wird die Datei umbenannt. Dieser Code wird wahrscheinlich einige Verbesserungen benötigen, aber die allgemeine Idee sollte Ihnen helfen, loszulegen.
Um alles oder nichts zuverlässig in eine Datei zu schreiben:
%Vor%Siehe auch Ist rename () ohne fsync () sicher? (wird von @Mihai Stan )
Um fehlende os.replace()
zu implementieren, können Sie MoveFileExW(src, dst, MOVEFILE_REPLACE_EXISTING)
(über win32file- oder ctypes-Module) unter Windows.
Bei mehreren Threads können Sie queue.put(data)
aufrufen
verschiedene Threads und schreibe in Datei in einem eigenen Thread:
queue.put(None)
unterbricht die Schleife.
Als Alternative könnten Sie Sperren (Threading, Multiprocessing, filelock) um den Zugriff zu synchronisieren:
%Vor%Sie können das Sperrdateimodul verwenden, um die Datei zu sperren, während Sie darauf schreiben. Jeder nachfolgende Versuch, es zu sperren, wird blockiert, bis die Sperre des vorherigen Prozesses / Threads freigegeben wurde.
%Vor%Auf diese Weise umgehen Sie Ihre Nebenläufigkeitsprobleme und müssen keine übrig gebliebene Datei bereinigen, wenn eine Ausnahme auftritt.
Das Konstrukt with
ist nützlich für die Bereinigung beim Beenden, aber nicht für das gewünschte Commit / Rollback-System. Ein try / except / else -Block kann dafür verwendet werden.
Sie sollten auch eine Standardmethode zum Erstellen des temporären Dateinamens verwenden, zum Beispiel mit dem Modul tempfile .
Und denken Sie daran fsync vor dem Umbenennen
Nachfolgend finden Sie den vollständigen modifizierten Code:
%Vor%Tags und Links python thread-safety file