programing

Python에서 파일 잠금

randomtip 2023. 6. 10. 16:25
반응형

Python에서 파일 잠금

파이썬으로 쓰기 위해 파일을 잠가야 합니다.여러 Python 프로세스에서 한 번에 액세스할 수 있습니다.온라인에서 일부 솔루션을 찾았지만 대부분은 유닉스 기반 또는 윈도우즈 기반인 경우가 많기 때문에 제 목적에 맞지 않습니다.

좋아요, 그래서 제가 작성한 코드로 진행하게 되었습니다. 여기, 내 웹사이트에서.(GitHub에서도 사용 가능).다음과 같은 방식으로 사용할 수 있습니다.

from filelock import FileLock

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

다른 솔루션은 많은 외부 코드 기반을 인용합니다.직접 작업하려면 Linux/DOS 시스템에서 각각의 파일 잠금 도구를 사용하는 크로스 플랫폼 솔루션의 코드가 있습니다.

try:
    # Posix based file locking (Linux, Ubuntu, MacOS, etc.)
    #   Only allows locking on writable files, might cause
    #   strange results for reading.
    import fcntl, os
    def lock_file(f):
        if f.writable(): fcntl.lockf(f, fcntl.LOCK_EX)
    def unlock_file(f):
        if f.writable(): 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        

지금이다,AtomicOpen에서 사용할 수 있습니다.with 일적으사블록는용하를 하는 블록open진술.

경고:

  • Windows에서 실행 중인 경우 종료가 호출되기 전에 Python이 충돌하면 잠금 동작이 어떻게 될지 모르겠습니다.
  • 여기에 제공되는 잠금은 절대적인 것이 아니라 권고 사항입니다.경쟁 가능성이 있는 모든 프로세스는 "AtomicOpen" 클래스를 사용해야 합니다.
  • 2020년 11월 9일 현재 이 코드는 Posix 시스템에서 쓰기 가능한 파일만 잠급니다.게시 후 이 날짜 이전의 어느 시점에서, 사용하는 것이 불법이 되었습니다.fcntl.lock읽기 전용 파일에 있습니다.

여기에는 교차 플랫폼 파일 잠금 모듈이 있습니다. 포털 로커

Kevin의 말처럼 여러 프로세스의 파일에 동시에 쓰는 것은 가능하면 피하고 싶은 일입니다.

문제를 데이터베이스에 저장할 수 있다면 SQLite를 사용할 수 있습니다.동시 액세스를 지원하고 자체 잠금을 처리합니다.

저는 그것을 위한 몇 가지 해결책을 찾고 있었고 저의 선택은 oos.concurrency였습니다.

강력하고 비교적 잘 문서화되어 있습니다.고정 장치를 기반으로 합니다.

기타 솔루션:

  • 포털 로커: exe 설치인 pywin32가 필요하므로 pip을 통해 사용할 수 없습니다.
  • 고정 장치: 문서화 불량
  • 잠금 파일: 더 이상 사용되지 않음
  • flufl.lock: POSIX 시스템을 위한 NFS 안전 파일 잠금.
  • 단순 집단 : 마지막 업데이트 2013-07.07.
  • zc.lockfile : 마지막 업데이트 2016-06(2017-03 기준)
  • lock_file : 2007-10년 마지막 업데이트

잠금 파일 선호 - 플랫폼 독립적인 파일 잠금

잠금은 플랫폼과 장치에 따라 다르지만 일반적으로 다음과 같은 몇 가지 옵션이 있습니다.

  1. flock() 또는 동등한 값을 사용합니다(OS에서 지원하는 경우).이것은 자문 잠금입니다. 잠금을 확인하지 않으면 무시됩니다.
  2. Lock-copy-move-unlock 방법론을 사용하여 파일을 복사하고 새 데이터를 쓴 다음 이동합니다(Move, not copy, move는 Linux에서 원자적 작업입니다. OS를 확인하십시오). 잠금 파일이 있는지 확인합니다.
  3. 디렉토리를 "잠금"으로 사용합니다.NFS는 flock()을 지원하지 않기 때문에 NFS에 쓰는 경우 이 작업이 필요합니다.
  4. 프로세스 간에 공유 메모리를 사용할 가능성도 있지만, 저는 한 번도 시도해 본 적이 없습니다. OS에 따라 매우 다릅니다.

이러한 모든 방법에서 잠금을 획득하고 테스트하려면 스핀 잠금(실패 후 재시도) 기술을 사용해야 합니다.이렇게 하면 동기화가 잘못될 수 있는 작은 창이 남기는 하지만 일반적으로 큰 문제가 되지 않을 정도로 작습니다.

크로스 플랫폼 솔루션을 찾고 있다면 다른 메커니즘을 통해 다른 시스템에 로깅하는 것이 좋습니다(위의 NFS 기술이 그 다음으로 좋습니다).

sqlite는 일반 파일과 동일한 NFS 제한을 받기 때문에 네트워크 공유의 sqlite 데이터베이스에 쓸 수 없으며 무료로 동기화를 얻을 수 없습니다.

다음은 Evan Fossmark의 구현과 유사filelock 라이브러리 사용 방법의 예입니다.

from filelock import FileLock

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

내의 코드with lock:블록은 스레드 세이프입니다. 즉, 다른 프로세스가 파일에 액세스하기 전에 완료됩니다.

OS 수준에서 단일 파일에 대한 액세스를 조정하는 것은 해결하고 싶지 않은 모든 종류의 문제로 가득 차 있습니다.

해당 파일에 대한 읽기/쓰기 액세스를 조정하는 별도의 프로세스를 사용하는 것이 가장 좋습니다.

파일을 잠그는 것은 일반적으로 플랫폼별 작업이므로 다른 운영 체제에서 실행될 가능성을 고려해야 할 수 있습니다.예:

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"

저는 같은 디렉토리/폴더 내에서 동일한 프로그램의 여러 복사본을 실행하고 오류를 기록하는 이런 상황에 대해 작업해 왔습니다.제 접근 방식은 로그 파일을 열기 전에 디스크에 "잠금 파일"을 쓰는 것이었습니다.프로그램은 계속하기 전에 "잠금 파일"이 있는지 확인하고 "잠금 파일"이 있는지 여부를 확인합니다.

코드는 다음과 같습니다.

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--- 위의 오래된 잠금에 대한 일부 의견을 검토한 후 "잠금 파일"의 고정성에 대한 검사를 추가하기 위해 코드를 편집했습니다.내 시스템에서 이 기능의 수천 번의 반복 타이밍이 제공되고 평균 0.002066...직전의 초:

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

바로 다음으로:

remove('errloglock')

그래서 저는 그 5배로 시작해서 정체를 표시하고 문제가 있는지 상황을 감시하기로 했습니다.

또한 타이밍 작업을 하면서 실제로 필요하지 않은 코드가 있다는 것을 깨달았습니다.

lock.close()

제가 오픈 스테이트먼트에 바로 이어서 이 편집에서 삭제했습니다.

이것은 저에게 효과가 있었습니다. 큰 파일을 차지하지 않고, 여러 작은 파일로 배포하고, 파일 Temp를 만들고, 파일 A를 삭제한 다음 파일 Temp를 A로 이름을 바꿉니다.

import os
import json

def Server():
    i = 0
    while i == 0:
        try:        
                with open(File_Temp, "w") as file:
                    json.dump(DATA, file, indent=2)
                if os.path.exists(File_A):
                    os.remove(File_A)
                os.rename(File_Temp, File_A)
                i = 1
        except OSError as e:
                print ("file locked: " ,str(e))
                time.sleep(1)
            
            
def Clients():
    i = 0
    while i == 0:
        try:
            if os.path.exists(File_A):
                with open(File_A,"r") as file:
                    DATA_Temp = file.read()
            DATA = json.loads(DATA_Temp)
            i = 1
        except OSError as e:
            print (str(e))
            time.sleep(1)

시나리오는 다음과 같습니다.사용자가 파일을 요청하여 작업을 수행합니다.그런 다음 사용자가 동일한 요청을 다시 보내면 첫 번째 요청이 완료될 때까지 두 번째 요청이 수행되지 않았음을 사용자에게 알립니다.그래서 저는 이 문제를 해결하기 위해 잠금 메커니즘을 사용합니다.

다음은 내 작업 코드입니다.

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

저는 회색빛 파이톤에서 단순하고 효과적인(!) 구현을 찾았습니다.

단순 사용 os.open(..., O_EXCL) + os.close()가 창에서 작동하지 않았습니다.

당신은 pylocker가 매우 유용하다는 것을 알게 될 것입니다.파일을 잠그거나 일반적으로 잠금 메커니즘에 사용할 수 있으며 여러 Python 프로세스에서 한 번에 액세스할 수 있습니다.

파일을 잠그는 방법은 다음과 같습니다.

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

Mac/POSIX만 필요하다면 외부 패키지 없이도 작동할 수 있습니다.

import sys
import stat
import os


filePath = "<PATH TO FILE>"
if sys.platform == 'darwin':
  flags = os.stat(filePath).st_flags
  if flags & ~stat.UF_IMMUTABLE:
    os.chflags(filePath, flags & stat.UF_IMMUTABLE)

파일 잠금을 해제하려면 변경만 하면 됩니다.

  if flags & stat.UF_IMMUTABLE:
    os.chflags(filePath, flags & ~stat.UF_IMMUTABLE)

언급URL : https://stackoverflow.com/questions/489861/locking-a-file-in-python

반응형