215 Stimmen

Sperren einer Datei in Python

Ich muss eine Datei zum Schreiben in Python sperren. Auf die Datei wird von mehreren Python-Prozessen gleichzeitig zugegriffen. Ich habe im Internet einige Lösungen gefunden, aber die meisten sind für meine Zwecke ungeeignet, da sie oft nur auf Unix oder Windows basieren.

16voto

Richard Levasseur Punkte 13763

Das Sperren ist plattform- und gerätespezifisch, aber im Allgemeinen haben Sie einige Möglichkeiten:

  1. Verwenden Sie flock() oder ein gleichwertiges Programm (wenn Ihr Betriebssystem es unterstützt). Dies ist eine beratende Sperre, die ignoriert wird, wenn Sie nicht auf die Sperre prüfen.
  2. Verwenden Sie eine lock-copy-move-unlock-Methode, bei der Sie die Datei kopieren, die neuen Daten schreiben und sie dann verschieben (verschieben, nicht kopieren - verschieben ist unter Linux eine atomare Operation - überprüfen Sie Ihr Betriebssystem) und prüfen Sie, ob die Sperrdatei vorhanden ist.
  3. Verwenden Sie ein Verzeichnis als "Schloss". Dies ist notwendig, wenn Sie auf NFS schreiben, da NFS flock() nicht unterstützt.
  4. Es gibt auch die Möglichkeit, gemeinsamen Speicher zwischen den Prozessen zu verwenden, aber das habe ich nie ausprobiert; es ist sehr betriebssystemspezifisch.

Bei all diesen Methoden müssen Sie eine Spin-Lock-Technik (Wiederholung nach Fehlschlag) verwenden, um die Sperre zu erhalten und zu testen. Dies lässt ein kleines Fenster für Fehlsynchronisation, aber es ist im Allgemeinen klein genug, um kein großes Problem darzustellen.

Wenn Sie nach einer plattformübergreifenden Lösung suchen, sollten Sie sich besser über einen anderen Mechanismus bei einem anderen System anmelden (die nächstbeste Möglichkeit ist die oben beschriebene NFS-Technik).

Beachten Sie, dass Sqlite über NFS den gleichen Beschränkungen unterliegt wie normale Dateien. Sie können also nicht in eine Sqlite-Datenbank auf einer Netzwerkfreigabe schreiben und die Synchronisierung kostenlos erhalten.

10voto

Josh Correia Punkte 2680

Hier ist ein Beispiel für die Verwendung der filelock Bibliothek, die ähnlich ist wie die Evan Fossmark's Umsetzung :

from filelock import FileLock

lockfile = r"c:\scr.txt"
lock = FileLock(lockfile + ".lock")
with lock:
    file = open(path, "w")
    file.write("123")
    file.close()

Jeder Code innerhalb der with lock: Block ist thread-sicher, d.h. er wird beendet, bevor ein anderer Prozess Zugriff auf die Datei hat.

7voto

Kevin Punkte 29597

Die Koordinierung des Zugriffs auf eine einzelne Datei auf Betriebssystemebene ist mit allerlei Problemen behaftet, die Sie wahrscheinlich nicht lösen wollen.

Am besten ist es, einen separaten Prozess zu haben, der den Lese- und Schreibzugriff auf diese Datei koordiniert.

3voto

Greg Hewgill Punkte 882617

Das Sperren einer Datei ist in der Regel ein plattformspezifischer Vorgang, so dass Sie möglicherweise die Möglichkeit berücksichtigen müssen, dass die Datei auf verschiedenen Betriebssystemen läuft. Zum Beispiel:

import os

def my_lock(f):
    if os.name == "posix":
        # Unix or OS X specific locking here
    elif os.name == "nt":
        # Windows specific locking here
    else:
        print "Unknown operating system, lock unavailable"

2voto

whitebeard Punkte 971

Ich habe an einer Situation wie dieser gearbeitet, in der ich mehrere Kopien desselben Programms im selben Verzeichnis/Ordner ausführe und Fehler protokolliere. Mein Ansatz war, eine "Sperrdatei" auf die Festplatte zu schreiben, bevor ich die Protokolldatei öffne. Das Programm prüft, ob die Sperrdatei vorhanden ist, bevor es fortfährt, und wartet, bis es an der Reihe ist, wenn die Sperrdatei vorhanden ist.

Hier ist der Code:

def errlogger(error):

    while True:
        if not exists('errloglock'):
            lock = open('errloglock', 'w')
            if exists('errorlog'): log = open('errorlog', 'a')
            else: log = open('errorlog', 'w')
            log.write(str(datetime.utcnow())[0:-7] + ' ' + error + '\n')
            log.close()
            remove('errloglock')
            return
        else:
            check = stat('errloglock')
            if time() - check.st_ctime > 0.01: remove('errloglock')
            print('waiting my turn')

EDIT--- Nachdem ich über einige der obigen Kommentare zu veralteten Sperren nachgedacht habe, habe ich den Code geändert, um eine Prüfung auf Veralterung der "Sperrdatei" hinzuzufügen. Die Zeitmessung von mehreren tausend Iterationen dieser Funktion auf meinem System ergab einen Durchschnitt von 0,002066... Sekunden von gerade zuvor:

lock = open('errloglock', 'w')

bis kurz danach:

remove('errloglock')

Also dachte ich mir, ich beginne mit dem Fünffachen dieser Menge, um den Stillstand anzuzeigen und die Situation auf Probleme zu überwachen.

Außerdem habe ich bei der Arbeit mit dem Timing festgestellt, dass ich ein Stück Code hatte, das nicht wirklich notwendig war:

lock.close()

den ich unmittelbar nach der offenen Aussage hatte, habe ich in dieser Bearbeitung entfernt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X