Sperren Sie eine Datei in Python

Jay Shaw 15 Februar 2024
  1. Auswirkungen der gemeinsamen Nutzung von Ressourcen durch mehrere Prozesse in Python
  2. Dateistatus und seine Auswirkungen auf das Sperren einer Datei in Python
  3. Sperren Sie eine Datei in Python
  4. Abschluss
Sperren Sie eine Datei in Python

Einige Ressourcen können in unserem täglichen Leben nicht von zwei Personen gleichzeitig genutzt werden, zum Beispiel eine Umkleidekabine. Jede Umkleidekabine verfügt über ein Schloss, das jeweils nur von einer Person betreten werden kann.

Wenn zwei Personen gleichzeitig Zugriff hätten, könnte dies zu Verwirrung und Verlegenheit führen. Aus diesem Grund wird die gemeinsam genutzte Ressource mit einer Sperre geschützt.

In ähnlicher Weise können beim Programmieren immer dann, wenn zwei Prozesse oder Threads dieselbe Ressource gemeinsam nutzen, Probleme entstehen, die durch die Verwendung von Sperren vermieden werden müssen. Dieser Artikel erklärt, wie man eine Datei in Python sperrt.

Auswirkungen der gemeinsamen Nutzung von Ressourcen durch mehrere Prozesse in Python

In diesem Abschnitt wird erläutert, warum das Sperren einer Datei in Python wichtig ist.

Das Programm hat zwei Prozesse: Der erste zahlt 1 $ auf ein Konto ein, ein anderer zieht 1 $ davon ab und am Ende wird der Saldo ausgedruckt. Diese Operation wird tausende Male in einer Schleife ausgeführt.

Technisch gesehen würde die Iteration zu keiner Änderung des Endsaldos führen, da die gleiche Zahl immer wieder hinzugefügt und abgezogen wird. Aber wenn das Programm kompiliert wird, sind die Ergebnisse variabel.

import multiprocessing


# Withdrawal function


def wthdrw(bal):
    for _ in range(10000):
        bal.value = bal.value - 1


# Deposit function


def dpst(bal):
    for _ in range(10000):
        bal.value = bal.value + 1


def transact():
    # initial balance
    bal = multiprocessing.Value("i", 100)

    # creating processes
    proc1 = multiprocessing.Process(target=wthdrw, args=(bal,))
    proc2 = multiprocessing.Process(target=dpst, args=(bal,))

    # starting processes
    proc1.start()
    proc2.start()

    # waiting for processes to finish
    proc1.join()
    proc2.join()

    # printing final balance
    print("Final balance = {}".format(bal.value))


if __name__ == "__main__":

    for _ in range(10):
        # Performing transaction process
        transact()

Ausgang:

C:\python38\python.exe "C:\Users\Win 10\main.py"
Final balance = 428
Final balance = 617
Final balance = -1327
Final balance = 1585
Final balance = -130
Final balance = -338
Final balance = -73
Final balance = -569
Final balance = 256
Final balance = -426

Process finished with exit code 0

Lassen Sie uns den Beispielcode aufschlüsseln, um zu verstehen, warum dies geschieht.

Dieses Programm verwendet das Python-Bibliothekspaket multiprocessing, um Methoden als Prozesse im Programm aufzurufen.

Die beiden Methoden wthdrw und dpst ziehen Geld ab und fügen es dem Konto hinzu. Sie haben einen Parameter, bal, der für Gleichgewicht steht.

Innerhalb der Methode wird der Wert von bal in einer for-Schleife inkrementiert oder dekrementiert. Die Iteration wird 10000 mal wiederholt.

Der bal.value ist die gemeinsame Ressource in diesem Programm.

# Method to Decrement
def wthdrw(bal):
    for _ in range(10000):
        bal.value = bal.value - 1

Eine neue Methode transact() startet die Prozesse übereinander. Innerhalb der Methode wird das Objekt bal, das den Anfangswert speichert, erstellt und der Saldo auf 100 gesetzt.

def transact():
    bal = multiprocessing.Value("i", 100)
    lock = multiprocessing.Lock()

Die multiprocessing-Bibliothek ermöglicht das Starten von Methoden als Prozesse unter Verwendung von Objekten. Beispielsweise wird die Methode wthdrw gestartet, indem ein Prozess proc1 erstellt wird.

Dieser Prozess zielt auf die Methode wthdrw und übergibt bal und ein leeres Objekt als Argumente.

proc1 = multiprocessing.Process(target=wthdrw, args=(bal,))

Ebenso wird ein proc2-Prozess erstellt, um die dpst-Methode zu starten. Sind beide Prozesse erstellt, werden sie mit process_name.start() gestartet.

proc1.start()
proc2.start()

Um einen laufenden Prozess zu schließen, wird die Syntax Prozessname.join() verwendet. Es stellt die Anforderung hinter einem laufenden Prozess in die Warteschlange, sodass das System wartet, bis der Prozess abgeschlossen ist, und ihn dann schließt.

Der Endsaldo wird nach Abschluss des Vorgangs gedruckt.

print("Final balance = {}".format(bal.value))

Die Variable __name__ wird auf __main gesetzt und die Methode transact() innerhalb einer for-Schleife aufgerufen. Dadurch können wir die Iterationen mehrmals beobachten, ohne Prozesse manuell aufrufen zu müssen.

if __name__ == "__main__":

    for _ in range(10):
        transact()

Als das Programm ausgeführt wurde, stellten wir fest, dass die Werte inkonsistent waren. Die gemeinsam genutzte Ressource bal.value ist nicht mit einer Sperre geschützt, sodass der andere Prozess den Wert bearbeitet, bevor der laufende Prozess beendet ist.

Sperren werden verwendet, um dieses Problem zu lösen. Das obige Programm wird gesperrt, indem bei beiden Methoden eine Sperre gesetzt wird; Auf diese Weise muss der Compiler warten, bis der nächste Prozess ausgeführt wird, bevor der vorherige abgeschlossen ist.

# Withdrawal function
def wthdrw(bal, lock):
    for _ in range(10000):
        # Locks
        lock.acquire()
        bal.value = bal.value - 1
        lock.release()

Die Anweisung lock.acquire() sperrt den Prozess, und darin wird der Wert von bal bearbeitet. Danach wird die Sperre mit lock.release() aufgehoben.

Dasselbe gilt für die dpst-Methode, und der Rest des Programms bleibt gleich.

Ausgang:

C:\python38\python.exe "C:\Users\Win 10\main.py"
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100
Final balance = 100

Process finished with exit code 0

Da wir wissen, was mit mehreren Prozessen mit gemeinsam genutzten Ressourcen passiert, werden wir uns eine wichtige Funktion ansehen, die zum Sperren einer Datei in Python erforderlich ist – Dateistatus.

Dateistatus und seine Auswirkungen auf das Sperren einer Datei in Python

Ein Dateistatus zeigt an, ob die Datei geöffnet oder geschlossen ist. Es ist wichtig, den Dateistatus zu kennen, um eine Datei in Python zu sperren, da Sperrvorgänge nur auf geöffnete Dateien angewendet werden können.

Angenommen, es gibt in Python eine Datei – myFile.txt. Wenn wir schreiben:

readMyFile = open("myFile.txt", "r").read()

Es ist unmöglich, den Status der Datei abzurufen, sie zu schließen oder irgendetwas anderes zu tun. Es gibt keinen Zugriff, weil es nirgendwo gespeichert ist.

Da es keinen Wert hätte, Informationen zu verwerfen und eine Müllsammlung unmöglich wäre, gibt es keine Magie, die es ermöglicht, verloren gegangenes Wissen wiederzugewinnen.

Vermeiden Sie es, Werte zu speichern, die in einer Variablen (einer Liste, einem dict-Mitglied oder einem Attribut einer Instanz) verwendet werden sollen, da dies deren Verwendung ermöglicht.

myFile = open("myFile.txt", "r")
readMyFile = myFile.read()
print(myFile.closed)

myFile.close()
print(myFile.closed)

Der obige Code speichert die Datei in einer Variablen myFile. Dann verwendet eine andere Variable, readMyFile, die Variable myFile, um das Objekt zu lesen.

Mit dieser Methode bleibt die Datei auch nach Abschluss des Lesevorgangs in einem geöffneten Zustand.

Die Syntax print(myFile.closed) zeigt den aktuellen Dateistatus; hier gibt es einen falschen Wert zurück, was bedeutet, dass es nicht geschlossen ist. Diese Datei wird explizit mit myFile.close() geschlossen.

Da das explizite Schließen von Dateien anfällig für menschliche Fehler ist, ist eine bessere Lösung die Verwendung der with-Anweisung.

with open("myFile.txt", "r") as myFile:
    readMyFile = myFile.read()

Jetzt wird myFile automatisch geschlossen, ohne dass es explizit geschlossen werden muss. Aus dem obigen Beispiel haben wir verstanden, dass effiziente Methoden zum Öffnen und Schließen von Dateien unerlässlich sind, um eine Datei in Python zu sperren.

Eine Datei kann nur in einem geöffneten Zustand gesperrt werden, und eine Datei kann nicht entsperrt werden, wenn keine Sperre vorhanden ist. Das Sperren einer Datei in Python muss immer innerhalb eines with-Blocks ausgeführt werden.

Sehen wir uns verschiedene Möglichkeiten an, eine Datei in Python zu sperren.

Sperren Sie eine Datei in Python

Dateisperren sind im Allgemeinen Bibliotheken von Drittanbietern, die in Skripten verwendet werden, um eine Datei zu sperren. In diesem Abschnitt werden einige weit verbreitete Dateisperren besprochen.

Sperren Sie eine Datei mit FileLock in Python

Dies ist eine plattformspezifische Bibliothek zum Sperren von Dateien, die sowohl unter Windows als auch unter UNIX funktioniert. Um es zu installieren, geben Sie den Befehl ein:

pip install filelock

Das Sperren einer Datei mit dieser Methode ist sehr einfach. Öffnen Sie die Datei mit FileLock innerhalb einer with-Anweisung, sodass die Datei geöffnet und vom System gesperrt wird.

Nach Abschluss des Vorgangs wird die Sperre am Ende der with-Anweisung automatisch aufgehoben.

from filelock import FileLock

with FileLock("myfile.txt"):
    print("Lock acquired.")

Ausgang:

C:\python38\python.exe "C:/main.py"
Lock acquired.

Process finished with exit code 0

Eine andere Möglichkeit, eine Datei in Python zu sperren, sind Timeouts. Dies hilft, ein Zeitlimit festzulegen, wenn eine Datei nicht gesperrt werden kann, wodurch Dateihandles für andere Prozesse freigegeben werden.

from filelock import FileLock

file = "example.txt"
lockfile = "example.txt.lock"

lock = FileLock(lockfile, timeout=5)

lock.acquire()
with open(file, "a") as f:
    print("File Locked")
    f.write("Add some data \n")
lock.release()


with open(file, "a") as f:
    f.write("Second time writing \n")

Die erste Codezeile importiert das FileLock-Modul aus der filelock-Bibliothek. Eine example.txt-Datei wird in einer variablen Datei gespeichert; diese Datei wird verwendet, um darauf zu schreiben.

Die Sperre wird nicht direkt auf die Originaldatei gesetzt, also wird eine temporäre Datei erstellt, wie example.txt.lock. Mit der Variable lock wird ein Lock-Objekt für das lockfile erzeugt und ein Timeout von 5 Sekunden gesetzt.

Diese Sperre kann mit der Anweisung lock.acquire gesetzt werden. Ein with-Block wird verwendet, um die Datei zu öffnen und in sie zu schreiben, während die lockfile verhindert, dass andere Prozesse auf die Originaldatei zugreifen, während sie geschrieben wird.

Abschliessend wird die Sperre mit lock.release() aufgehoben. Ein anderer Prozess öffnet dann die Datei und schreibt erfolgreich darauf.

Ausgang:

C:\python38\python.exe "C:/main.py"
File Locked

Process finished with exit code 0

Python-Sperrdatei mit FileLock - Ausgabe

Um eine Datei mit Python zu sperren, können wir die Sperren auch verschachtelt platzieren:

from filelock import Timeout, FileLock

lock = FileLock("high_ground.txt.lock")
with lock:
    with open("high_ground.txt", "a") as f:
        f.write("You were the chosen one.")

Im obigen Beispiel wird ein lock-Objekt mit einer Datei namens high_ground.txt erstellt, um eine Datei in Python zu sperren. Das Schloss befindet sich in einem Block; darin wird die Datei mit einem anderen Block gelesen.

Diese Methode erfordert weniger Code als die vorherige.

Der FileLock ist plattformabhängig. Wenn jede Anwendungsinstanz auf derselben Plattform läuft, verwenden Sie ein FileLock; Verwenden Sie andernfalls ein SoftFileLock.

Ein SoftFileLock ist plattformunabhängig und überwacht nur die Existenz der Sperrdatei. Aus diesem Grund ist es extrem portabel und friert eher ein, wenn die Anwendung abstürzt.

Löschen Sie in solchen Fällen die Sperrdatei.

File Locker kann auch mit einem Ausnahmebehandlungsblock verwendet werden:

try:
    with lock.acquire(timeout=10):
        with open(file_path, "a") as f:
            f.write("I have a bad feeling about this.")
except Timeout:
    print("Another instance of this application currently holds the lock.")

Dieses Code-Snippet platziert eine Sperre innerhalb des try-Blocks und gibt eine Zeitüberschreitung von 10 Sekunden. Dann wird die Datei in ein verschachteltes with geschrieben.

Innerhalb des Ausnahme-Blocks wird eine entsprechende Meldung ausgegeben, wenn die Anwendung das Zeitlimit überschreitet.

Sperren Sie eine Datei mit PortaLocker in Python

Eine weitere Möglichkeit, eine Datei in Python zu sperren, ist die Verwendung der Bibliothek namens portalocker, die eine einfache API zum Sperren von Dateien bietet.

Es ist wichtig, sich daran zu erinnern, dass Sperren auf Linux- und Unix-Systemen standardmäßig empfohlen werden. Das obligatorische Sperren von Dateien kann unter Linux aktiviert werden, indem dem Mount-Befehl die Option -o mand hinzugefügt wird.

Um es zu installieren, geben Sie den Befehl ein:

pip install "portalocker[redis]"

Das Sperren einer Datei in Python mit portalocker ist ähnlich wie die FileLock-Methode, aber viel einfacher.

import portalocker

file = "example.txt"
with portalocker.Lock(file, "a") as fh:
    fh.write("first instance")
    print("waiting for your input")
    input()

Ausgang:

C:\python38\python.exe "C:/main.py"

lock acquired
waiting for your input

Im obigen Code importiert die erste Zeile das Bibliothekspaket. Die Sperre wird mit der Syntax portalocker.RedisLock() erstellt und die Sperre mit einer with-Anweisung gesetzt.

Um die Sperre innerhalb eines Timeouts zu platzieren, verwenden Sie:

import portalocker

file = "example.txt"
with portalocker.Lock("file", timeout=1) as fh:
    print("writing some stuff to my cache...", file=fh)

Ausgang:

Python-Sperrdatei mit PortaLocker - Ausgabe

Abschluss

Dieser Artikel erklärt, wie man eine Datei in Python sperrt und warum es wichtig ist. Der Leser kann nach dem Lesen dieses Artikels Open-State-Dateien erstellen und sie leicht sperren.

Verwandter Artikel - Python File