개발/Python

Python에서 파일 잠금

MinorMan 2021. 1. 9. 23:03
반응형

<질문>

파이썬으로 쓰기 위해 파일을 잠 가야합니다. 한 번에 여러 Python 프로세스에서 액세스됩니다. 온라인에서 몇 가지 솔루션을 찾았지만 대부분은 Unix 기반 또는 Windows 기반이기 때문에 내 목적에 맞지 않습니다.


<답변1>

좋아, 그래서 내가 작성한 코드로 끝났다여기 내 웹 사이트에서링크가 죽었습니다. archive.org에서보기(also available on GitHub). 다음과 같은 방식으로 사용할 수 있습니다.

from filelock import FileLock

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

<답변2>

여기에 크로스 플랫폼 파일 잠금 모듈이 있습니다.Portalocker

Kevin이 말했듯이 한 번에 여러 프로세스에서 파일에 쓰는 것은 가능한 한 피하고 싶은 것입니다.

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


<답변3>

다른 솔루션은 많은 외부 코드 기반을 인용합니다. 직접 수행하려는 경우 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읽기 전용 파일에서.

<답변4>

나는 선호한다잠금 파일— 플랫폼 독립적 인 파일 잠금


<답변5>

이를 수행하기 위해 몇 가지 솔루션을 찾고 있었고 제 선택은oslo.concurrency

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

기타 솔루션 :

  • Portalocker: exe 설치 인 pywin32가 필요하므로 pip를 통해 불가능
  • fasteners: 제대로 문서화되지 않음
  • lockfile: 지원 중단됨
  • flufl.lock: POSIX 시스템에 대한 NFS 안전 파일 잠금.
  • simpleflock: 최종 업데이트 2013-07
  • zc.lockfile: 최종 업데이트 2016-06 (2017-03 기준)
  • lock_file: 2007-10 년 마지막 업데이트

<답변6>

잠금은 플랫폼 및 장치별로 다르지만 일반적으로 몇 가지 옵션이 있습니다.

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

이러한 모든 방법에 대해 잠금 획득 및 테스트를 위해 스핀 잠금 (실패 후 재시도) 기술을 사용해야합니다. 이것은 잘못된 동기화를위한 작은 창을 남기지 만 일반적으로 큰 문제가되지 않을만큼 충분히 작습니다.

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

sqlite는 일반 파일과 동일한 NFS 제약 조건을 따르므로 네트워크 공유의 sqlite 데이터베이스에 쓸 수 없으며 무료로 동기화 할 수 없습니다.


<답변7>

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

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


<답변8>

파일 잠금은 일반적으로 플랫폼 별 작업이므로 다른 운영 체제에서 실행할 수있는 가능성을 허용해야 할 수 있습니다. 예를 들면 :

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"

<답변9>

나는 동일한 디렉토리 / 폴더 내에서 동일한 프로그램의 여러 복사본을 실행하고 오류를 로깅하는 이와 같은 상황에서 작업하고 있습니다. 내 접근 방식은 로그 파일을 열기 전에 디스크에 "잠금 파일"을 쓰는 것이 었습니다. 프로그램은 계속하기 전에 "잠금 파일"이 있는지 확인하고 "잠금 파일"이 있으면 차례를 기다립니다.

다음은 코드입니다.

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

편집 --- 위의 오래된 잠금에 대한 몇 가지 주석을 고려한 후 코드를 편집하여 "잠금 파일"의 오래된 검사를 추가했습니다. 내 시스템에서이 함수를 수천 번 반복하면 바로 전보다 평균 0.002066 ... 초가됩니다.

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

바로 후에 :

remove('errloglock')

그래서 저는 그 양의 5 배로 시작하여 부실함을 표시하고 문제에 대한 상황을 모니터링 할 것이라고 생각했습니다.

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

lock.close()

공개 성명 바로 뒤에 갔기 때문에이 편집에서 제거했습니다.


<답변10>

에 추가하려면Evan Fossmark's answer, 다음은 사용 방법의 예입니다.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:블록은 스레드로부터 안전하므로 다른 프로세스가 파일에 액세스하기 전에 완료됩니다.


<답변11>

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

내 작업 코드는 다음과 같습니다.

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

<답변12>

나는 간단하고 일했다 (!)implementation그리 즐드 파이썬에서.

간단한 사용 os.open (..., O_EXCL) + os.close ()는 Windows에서 작동하지 않았습니다.


<답변13>

당신은 찾을 수 있습니다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
반응형