파이썬에서 파일 잠그기

Jay Shaw 2023년6월21일
  1. Python에서 여러 프로세스에 의한 리소스 공유의 영향
  2. 파일 상태 및 Python에서 파일 잠금에 미치는 영향
  3. 파이썬에서 파일 잠그기
  4. 결론
파이썬에서 파일 잠그기

일부 리소스(예: 탈의실)는 일상 생활에서 두 사람이 동시에 액세스할 수 없습니다. 모든 탈의실에는 한 번에 한 사람만 접근할 수 있는 잠금 장치가 있습니다.

두 사람이 동시에 액세스할 수 있으면 혼란과 당혹감을 유발할 수 있습니다. 그래서 공유 리소스가 잠금으로 보호되는 이유입니다.

마찬가지로 프로그래밍에서 두 프로세스 또는 스레드가 동일한 리소스를 공유할 때마다 잠금을 사용하여 피해야 하는 문제가 발생할 수 있습니다. 이 기사에서는 Python에서 파일을 잠그는 방법을 설명합니다.

Python에서 여러 프로세스에 의한 리소스 공유의 영향

이 섹션에서는 Python에서 파일을 잠그는 것이 중요한 이유를 설명합니다.

이 프로그램에는 두 가지 프로세스가 있습니다. 첫 번째 프로세스는 계정에 $1를 입금하고 다른 프로세스는 계정에서 $1를 차감한 다음 마지막에 잔액을 인쇄합니다. 이 작업은 루프 내에서 수천 번 실행됩니다.

기술적으로 반복은 동일한 숫자가 계속해서 추가되고 차감되므로 최종 잔액에 변화가 없습니다. 그러나 프로그램이 컴파일되면 결과는 다양합니다.

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()

출력:

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

예제 코드를 분석하여 왜 이런 일이 발생하는지 이해해 봅시다.

이 프로그램은 Python 라이브러리 패키지인 multiprocessing을 사용하여 프로그램의 프로세스로 메서드를 호출합니다.

wthdrwdpst의 두 가지 방법은 계정에서 돈을 공제하고 추가합니다. 하나의 매개변수인 bal은 균형을 나타냅니다.

메서드 내에서 bal 값은 for 루프 내에서 증가하거나 감소합니다. 반복은 10000번 반복됩니다.

bal.value는 이 프로그램의 공유 리소스입니다.

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

새 메서드인 transact()는 프로세스를 차례로 시작합니다. 메서드 내에서 초기 값을 저장하는 bal 개체가 생성되고 잔액은 100으로 설정됩니다.

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

multiprocessing 라이브러리를 사용하면 개체를 사용하는 프로세스로 메서드를 시작할 수 있습니다. 예를 들어 wthdrw 메서드는 proc1 프로세스를 생성하여 시작됩니다.

이 프로세스는 wthdrw 메서드를 대상으로 하며 bal 및 빈 개체를 인수로 전달합니다.

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

마찬가지로 proc2 프로세스가 생성되어 dpst 메서드를 시작합니다. 두 프로세스가 생성되면 process_name.start()를 사용하여 시작됩니다.

proc1.start()
proc2.start()

실행 중인 프로세스를 닫으려면 process_name.join() 구문이 사용됩니다. 실행 중인 프로세스 뒤에서 요청을 대기하므로 시스템은 프로세스가 완료될 때까지 기다린 다음 닫힙니다.

최종 잔액은 프로세스가 완료된 후 인쇄됩니다.

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

__name__ 변수는 __main으로 설정되고 transact() 메서드는 for 루프 내에서 호출됩니다. 이를 통해 수동으로 프로세스를 호출하지 않고도 반복을 여러 번 관찰할 수 있습니다.

if __name__ == "__main__":

    for _ in range(10):
        transact()

프로그램을 실행했을 때 값이 일치하지 않는 것을 발견했습니다. 공유 리소스 bal.value는 잠금으로 보호되지 않으므로 실행 중인 프로세스가 완료되기 전에 다른 프로세스가 값을 편집합니다.

이 문제를 해결하기 위해 잠금이 사용됩니다. 위의 프로그램은 두 방법 모두에 잠금을 설정하여 잠급니다. 이런 식으로 컴파일러는 이전 프로세스가 완료되기 전에 다음 프로세스를 실행하기 위해 기다려야 합니다.

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

lock.acquire() 문은 프로세스를 잠그고 그 내부에서 bal 값이 편집됩니다. 그런 다음 lock.release()를 사용하여 잠금을 해제합니다.

dpst 방법에도 동일하게 적용되며 나머지 프로그램은 동일하게 유지됩니다.

출력:

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

리소스를 공유하는 여러 프로세스에 어떤 일이 발생하는지 알고 있으므로 Python에서 파일을 잠그는 데 필요한 중요한 기능인 파일 상태를 살펴보겠습니다.

파일 상태 및 Python에서 파일 잠금에 미치는 영향

파일 상태는 파일이 열려 있는지 닫혀 있는지 보여줍니다. 잠금 작업은 열린 파일에만 배치할 수 있기 때문에 Python에서 파일을 잠그려면 파일 상태를 아는 것이 중요합니다.

Python에 ‘myFile.txt’라는 파일이 있다고 가정합니다. 우리가 쓸 때:

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

파일의 상태를 가져오거나 닫거나 다른 작업을 수행하는 것은 불가능합니다. 어디에도 저장되어 있지 않기 때문에 접근이 불가능합니다.

정보를 버려도 가치가 없고 가비지 수집이 불가능하기 때문에 잃어버린 지식을 되찾는 마법은 없다.

사용할 수 있도록 변수(목록, dict 멤버 또는 인스턴스의 속성)에 사용하려는 값을 저장하지 마십시오.

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

myFile.close()
print(myFile.closed)

위의 코드는 myFile 변수에 파일을 저장합니다. 그런 다음 다른 변수인 readMyFilemyFile 변수를 사용하여 개체를 읽습니다.

이 방법을 사용하면 읽기가 완료된 후에도 파일을 열린 상태로 유지합니다.

print(myFile.closed) 구문은 현재 파일 상태를 보여줍니다. 여기서는 닫히지 않았음을 의미하는 false 값을 반환합니다. 이 파일은 myFile.close()를 사용하여 명시적으로 닫힙니다.

명시적으로 파일을 닫으면 인적 오류가 발생하기 쉬우므로 더 나은 해결책은 with 문을 사용하는 것입니다.

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

이제 myFile은 명시적으로 닫을 필요 없이 자동으로 닫힙니다. 위의 예에서 우리는 파일을 열고 닫는 효율적인 방법이 파이썬에서 파일을 잠그는 데 필수적이라는 것을 이해했습니다.

파일은 열린 상태에서만 잠글 수 있으며 잠금이 없으면 파일을 잠금 해제할 수 없습니다. Python에서 파일 잠금은 항상 with 블록 내에서 실행되어야 합니다.

파이썬에서 파일을 잠그는 몇 가지 방법을 살펴보겠습니다.

파이썬에서 파일 잠그기

파일 잠금은 일반적으로 스크립트 내에서 파일을 잠그는 데 사용되는 타사 라이브러리입니다. 이 섹션에서는 널리 사용되는 일부 파일 잠금에 대해 설명합니다.

Python에서 FileLock을 사용하여 파일 잠금

이것은 Windows와 UNIX 모두에서 작동하는 플랫폼별 파일 잠금 라이브러리입니다. 설치하려면 다음 명령을 입력하십시오.

pip install filelock

이 방법으로 파일을 잠그는 것은 매우 간단합니다. with 문 안에 FileLock을 사용하여 파일을 열면 파일이 열리고 시스템이 잠급니다.

프로세스가 완료된 후 with문의 끝에서 잠금이 자동으로 해제됩니다.

from filelock import FileLock

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

출력:

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

Process finished with exit code 0

Python에서 파일을 잠그는 또 다른 방법은 시간 제한을 사용하는 것입니다. 이렇게 하면 파일을 잠글 수 없는 경우 시간 제한을 두어 다른 프로세스에 대한 파일 핸들을 해제할 수 있습니다.

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")

코드의 첫 번째 줄은 filelock 라이브러리에서 FileLock 모듈을 가져옵니다. example.txt 파일은 변수 파일 내에 저장됩니다. 이 파일은 쓰기에 사용됩니다.

잠금은 원본 파일에 직접 적용되지 않으므로 example.txt.lock과 같은 임시 파일이 생성됩니다. lock 변수는 lockfile에 대한 잠금 개체를 생성하는 데 사용되며 5초의 제한 시간이 설정됩니다.

이 잠금은 lock.acquire 문을 사용하여 배치할 수 있습니다. with 블록은 파일을 열고 파일에 쓰는 데 사용되는 반면 lockfile은 원본 파일이 기록되는 동안 다른 프로세스가 원본 파일에 액세스하지 않도록 합니다.

마지막으로 lock.release()를 사용하여 잠금을 해제합니다. 그런 다음 다른 프로세스가 파일을 열고 성공적으로 기록합니다.

출력:

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

Process finished with exit code 0

FileLock을 사용하는 Python 잠금 파일 - 출력

Python을 사용하여 파일을 잠그려면 잠금을 중첩 방식으로 배치할 수도 있습니다.

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.")

위의 예에서 lock 개체는 high_ground.txt라는 파일로 생성되어 Python에서 파일을 잠급니다. 잠금은 블록 안에 배치됩니다. 그 안에는 다른 블록을 사용하여 파일을 읽습니다.

이 방법은 이전 방법보다 적은 코드가 필요합니다.

FileLock은 플랫폼에 따라 다릅니다. 모든 애플리케이션 인스턴스가 동일한 플랫폼에서 작동하는 경우 FileLock을 사용하십시오. 그렇지 않으면 SoftFileLock을 사용하십시오.

SoftFileLock은 플랫폼과 독립적이며 잠금 파일의 존재만 모니터링합니다. 이 때문에 매우 이식성이 뛰어나고 응용 프로그램이 충돌하면 정지될 가능성이 더 높습니다.

이러한 상황에서는 잠금 파일을 삭제하십시오.

파일 보관함은 예외 처리 블록과 함께 사용할 수도 있습니다.

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.")

이 코드 스니펫은 try 블록 내부에 잠금을 배치하고 10초 동안 시간 초과를 제공합니다. 그런 다음 중첩된 with 안에 파일이 기록됩니다.

제외 블록 내에서 응용 프로그램이 시간 초과되면 적절한 메시지가 인쇄되도록 설정됩니다.

Python에서 PortaLocker를 사용하여 파일 잠금

Python에서 파일을 잠그는 또 다른 옵션은 파일 잠금을 위한 간단한 API를 제공하는 portalocker라는 라이브러리를 사용하는 것입니다.

잠금은 Linux 및 Unix 시스템에서 기본적으로 권장 사항임을 기억하는 것이 중요합니다. 마운트 명령에 -o mand 옵션을 추가하여 Linux에서 필수 파일 잠금을 활성화할 수 있습니다.

설치하려면 다음 명령을 입력하십시오.

pip install "portalocker[redis]"

portalocker를 사용하여 Python에서 파일을 잠그는 것은 FileLock 방법과 유사하지만 훨씬 간단합니다.

import portalocker

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

출력:

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

lock acquired
waiting for your input

위의 코드에서 첫 번째 줄은 라이브러리 패키지를 가져옵니다. 잠금은 portalocker.RedisLock() 구문을 사용하여 생성되며 잠금은 with 문을 사용하여 배치됩니다.

제한 시간 내에 잠금을 설정하려면 다음을 사용하십시오.

import portalocker

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

출력:

PortaLocker를 사용하는 Python 잠금 파일 - 출력

결론

이 기사에서는 Python에서 파일을 잠그는 방법과 이것이 중요한 이유를 설명합니다. 독자는 이 기사를 읽은 후 쉽게 개방 상태 파일을 만들고 잠금을 설정할 수 있습니다.

관련 문장 - Python File