Frage

Ich brauche eine Datei zu sperren, in Python zu schreiben. Es wird sofort von mehreren Python Prozesse zugegriffen werden. Ich habe einige Lösungen online gefunden, aber die meisten nicht für meine Zwecke, wie sie sind oft nur Unix oder Windows basiert.

War es hilfreich?

Lösung

In Ordnung, so landete ich mit dem Code steigen Ich schrieb hier, auf meiner Website Link ist tot, Blick auf archive.org ( auch auf GitHub ). Ich kann es in der folgenden Art und Weise verwendet werden:

from filelock import FileLock

with FileLock("myfile.txt"):
    # work with the file as it is now locked
    print("Lock acquired.")

Andere Tipps

Es ist eine plattformübergreifende Dateiverriegelungsmodul hier: Portalocker

Obwohl als Kevin sagt, auf einmal in eine Datei von mehreren Prozessen zu schreiben ist etwas, das Sie, wenn möglich zu vermeiden.

Wenn Sie Ihr Problem in eine Datenbank Schuhanzieher können, könnten Sie SQLite verwenden. Es unterstützt den gleichzeitigen Zugriff und behandelt seine eigene Verriegelung.

Die anderen Lösungen zitieren viele externe Codebasen. Wenn Sie lieber es selbst zu tun, hier ist ein Code für eine plattformübergreifende Lösung, die die jeweilige Datei verwendet Tools unter Linux / DOS-Systemen zu verriegeln.

try:
    # Posix based file locking (Linux, Ubuntu, MacOS, etc.)
    import fcntl, os
    def lock_file(f):
        fcntl.lockf(f, fcntl.LOCK_EX)
    def unlock_file(f):
        fcntl.lockf(f, fcntl.LOCK_UN)
except ModuleNotFoundError:
    # Windows file locking
    import msvcrt, os
    def file_size(f):
        return os.path.getsize( os.path.realpath(f.name) )
    def lock_file(f):
        msvcrt.locking(f.fileno(), msvcrt.LK_RLCK, file_size(f))
    def unlock_file(f):
        msvcrt.locking(f.fileno(), msvcrt.LK_UNLCK, file_size(f))


# Class for ensuring that all file operations are atomic, treat
# initialization like a standard call to 'open' that happens to be atomic.
# This file opener *must* be used in a "with" block.
class AtomicOpen:
    # Open the file with arguments provided by user. Then acquire
    # a lock on that file object (WARNING: Advisory locking).
    def __init__(self, path, *args, **kwargs):
        # Open the file and acquire a lock on the file before operating
        self.file = open(path,*args, **kwargs)
        # Lock the opened file
        lock_file(self.file)

    # Return the opened file object (knowing a lock has been obtained).
    def __enter__(self, *args, **kwargs): return self.file

    # Unlock the file and close the file object.
    def __exit__(self, exc_type=None, exc_value=None, traceback=None):        
        # Flush to make sure all buffered contents are written to file.
        self.file.flush()
        os.fsync(self.file.fileno())
        # Release the lock on the file.
        unlock_file(self.file)
        self.file.close()
        # Handle exceptions that may have come up during execution, by
        # default any exceptions are raised to the user.
        if (exc_type != None): return False
        else:                  return True        

Nun kann AtomicOpen in einem with Block verwendet werden, wo man normalerweise eine open Anweisung verwenden.

. ACHTUNG: Wenn auf Windows und Python läuft, bevor stürzt exit genannt wird, ich bin mir nicht sicher, wie das Schloss Verhalten würde

ACHTUNG: Die Verriegelungs- hier ist Beratung, nicht absolut. Alle potenziell konkurrierende Prozesse müssen die „AtomicOpen“ Klasse verwenden.

Ich ziehe lockfile - Plattformunabhängige Dateisperren

Locking ist Plattform und gerätespezifisch, aber im Allgemeinen, Sie haben ein paar Optionen:

  1. Verwenden flock () oder gleichwertig (wenn Ihr o unterstützt). Dies ist beratender Sperrungen, wenn Sie für die Sperre überprüfen, seine ignoriert.
  2. Verwenden Sie eine Lock-Kopie-move-unlock-Methodik, in dem Sie die Datei kopieren, um die neuen Daten schreiben, verschieben Sie es dann (verschieben, nicht kopieren - Bewegung ist eine atomare Operation in Linux - überprüfen Sie Ihre OS), und Sie Check für die Existenz der Sperrdatei.
  3. Verwenden Sie ein Verzeichnis als „Lock“. Dies ist notwendig, wenn Sie NFS schreiben, da NFS nicht Herde unterstützen ().
  4. Es gibt auch die Möglichkeit, gemeinsam genutzten Speicher zwischen den Prozessen, aber ich habe nie versucht, das; es ist sehr OS-spezifisch.

Für all diese Methoden, werden Sie einen Spin-Lock verwenden müssen (Retry-After-Ausfall) Technik zum Erfassen und das Schloss zu testen. Dies macht ein kleines Fenster für Fehl-Synchronisierung verlassen, aber sein im Allgemeinen klein genug, um nicht ein großes Problem sein.

Wenn Sie nach einer Lösung suchen, die Cross-Plattform ist, dann sind Sie besser dran, über einen anderen Mechanismus zu einem anderen System anzumelden (die nächste beste Sache ist die NFS-Technik oben).

Beachten Sie, dass SQLite auf die gleichen Einschränkungen über NFS unterliegt, dass normale Dateien sind, so dass Sie nicht zu einer SQLite-Datenbank auf einer Netzwerkfreigabe und kostenlos bekommen Synchronisation schreiben können.

Ich habe an mehreren Lösungen gesucht, dass meine Wahl gewesen zu tun oslo.concurrency

Es ist mächtig und relativ gut dokumentiert. Es basiert auf Befestigungen.

Andere Lösungen:

Die Koordination Zugriff auf eine einzelne Datei auf OS-Ebene ist mit allen Arten von Problemen behaftet, die Sie wollen wahrscheinlich nicht lösen.

Ihre beste Wette ist, einen separaten Prozess haben, der / Schreibzugriff auf die Datei lesen Koordinaten.

Eine Datei Sperren in der Regel eine plattformspezifische Bedienung, so dass Sie auf verschiedenen Betriebssystemen laufen, die Möglichkeit zu ermöglichen, benötigen. 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"

Ich habe wie diese auf eine Situation gearbeitet, wo ich mehrere Kopien des gleichen Programms aus und in denselben Verzeichnis / Ordner und Protokollieren von Fehlern führen. Mein Ansatz war es, eine „Sperrdatei“ auf die Disk zu schreiben, bevor Sie die Protokolldatei zu öffnen. Das Programm überprüft das Vorhandensein der „Lock-Datei“, bevor Sie fortfahren, und wartet darauf, seinerseits, wenn die „Sperrdatei“ existiert.

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 einige der Kommentare über veraltete Sperren über oben ich den Code hinzuzufügen, um einen Scheck für staleness der bearbeiteten „Lock-Datei.“ Timing mehr tausend Iterationen dieser Funktion auf meinem System gab und durchschnittlich 0.002066 ... Sekunden von kurz vor:

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

, um kurz nach:

remove('errloglock')

so dachte ich, ich mit 5-mal die Menge beginnt staleness, um anzuzeigen, und die Situation für Probleme zu überwachen.

Auch, wie ich mit dem Zeitpunkt arbeitete, erkannte ich, dass ich ein Stück Code hatte, die nicht wirklich notwendig war:

lock.close()

, die hatte folgend ich sofort die Open-Anweisung, so habe ich es in dieser Bearbeitung entfernt.

Das Szenario , wie das ist: Der Benutzer fordert eine Datei, etwas zu tun. Dann, wenn der Benutzer wieder die gleiche Anforderung sendet, informiert es den Benutzer, dass die zweite Anforderung nicht, bis die erste Anforderung abgeschlossen ist erfolgt. Deshalb verwende ich Lock-Mechanismus dieses Problem zu behandeln.

Hier ist mein Arbeits Code:

from lockfile import LockFile
lock = LockFile(lock_file_path)
status = ""
if not lock.is_locked():
    lock.acquire()
    status = lock.path + ' is locked.'
    print status
else:
    status = lock.path + " is already locked."
    print status

return status

fand ich eine einfache und arbeitete (!) Implementierung von ergrauten-python.

Einfache Verwendung os.open (..., O_EXCL) + os.close () funktionierten nicht auf Windows.

Sie können feststellen, pylocker sehr nützlich. Es kann verwendet werden, um eine Datei zu sperren oder Mechanismen im allgemeinen Verriegelungs- und können gleichzeitig von mehreren Python Prozesse zugegriffen werden.

Wenn Sie einfach eine Datei hier sperren wollen, wie es funktioniert:

import uuid
from pylocker import Locker

#  create a unique lock pass. This can be any string.
lpass = str(uuid.uuid1())

# create locker instance.
FL = Locker(filePath='myfile.txt', lockPass=lpass, mode='w')

# aquire the lock
with FL as r:
    # get the result
    acquired, code, fd  = r

    # check if aquired.
    if fd is not None:
        print fd
        fd.write("I have succesfuly aquired the lock !")

# no need to release anything or to close the file descriptor, 
# with statement takes care of that. let's print fd and verify that.
print fd
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top