답변:
좋아, 그래서 나는 여기에 쓴 코드로 끝났고 , 내 웹 사이트 링크가 죽었습니다. archive.org ( 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
크로스 플랫폼 파일 잠금 모듈이 있습니다 : Portalocker
Kevin이 말했듯이 한 번에 여러 프로세스에서 파일에 쓰는 것은 가능한 한 피하고 싶은 일입니다.
문제를 데이터베이스에 삽입 할 수 있다면 SQLite를 사용할 수 있습니다. 동시 액세스를 지원하고 자체 잠금을 처리합니다.
다른 솔루션은 많은 외부 코드 기반을 인용합니다. 직접 수행하려면 Linux / DOS 시스템에서 해당 파일 잠금 도구를 사용하는 크로스 플랫폼 솔루션에 대한 코드가 있습니다.
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
이제 일반적으로 명령문을 사용하는 블록에서 AtomicOpen
사용할 수 있습니다 .with
open
경고 : 종료 가 호출 되기 전에 Windows에서 실행 중이고 Python이 충돌 하면 잠금 동작이 무엇인지 잘 모르겠습니다.
경고 : 여기에 제공된 잠금은 절대적인 것이 아니라 권고입니다. 잠재적으로 경쟁중인 모든 프로세스는 "AtomicOpen"클래스를 사용해야합니다.
unlock_file
리눅스에서 파일 플래그 fcntl
와 함께 다시 호출해서는 안 LOCK_UN
됩니까?
__exit__
당신 close
외부 후 잠금 unlock_file
. 런타임 중에 런타임이 데이터를 플러시 (즉, 쓰기) 할 수 있다고 생각합니다 close
. 나는 일 개해야 믿을 flush
와 fsync
잠금 아래 중 잠금 외부에서 작성되어 있는지 추가 데이터를 만들기 위해 close
.
flush
과 fsync
. 전화하기 전에 제안한 두 줄을 추가했습니다 unlock
. 다시 테스트했는데 경쟁 조건이 해결 된 것으로 보입니다.
lockfile을 선호합니다 — 플랫폼 독립적 인 파일 잠금
나는 그것을하기 위해 여러 가지 해결책을 찾고 있으며 내 선택은 오슬로입니다.
강력하고 비교적 잘 문서화되어 있습니다. 패스너를 기반으로합니다.
다른 솔루션 :
잠금은 플랫폼 및 장치마다 다르지만 일반적으로 몇 가지 옵션이 있습니다.
이러한 모든 방법에 대해 잠금을 획득하고 테스트하려면 스핀 잠금 (실패 후 재시도) 기술을 사용해야합니다. 이로 인해 잘못된 동기화를위한 작은 창이 남지만 일반적으로 큰 문제가되지 않을 정도로 작습니다.
플랫폼 간 솔루션을 찾고 있다면 다른 메커니즘을 통해 다른 시스템에 로깅하는 것이 좋습니다 (다음의 가장 좋은 방법은 위의 NFS 기술입니다).
sqlite는 일반 파일의 NFS와 동일한 제약 조건을 따르므로 네트워크 공유의 sqlite 데이터베이스에 쓸 수 없으며 무료로 동기화 할 수 없습니다.
os.rename
이제 Python 3.3 이후 Win32에서 원자 적입니다 : bugs.python.org/issue8828
OS 수준에서 단일 파일에 대한 액세스 조정은 해결하고 싶지 않은 모든 종류의 문제로 가득 차 있습니다.
최선의 방법은 해당 파일에 대한 읽기 / 쓰기 액세스를 조정하는 별도의 프로세스입니다.
flock
. "자신의 뮤텍스와 그것들을 관리하기위한 데몬 프로세스를 롤링하는"접근 방식은 해결하기 위해 다소 극단적이고 복잡한 접근 방법처럼 보입니다.
파일 잠금은 일반적으로 플랫폼 별 작업이므로 다른 운영 체제에서 실행될 가능성을 허용해야 할 수도 있습니다. 예를 들면 다음과 같습니다.
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')
편집 --- 위의 부실 잠금에 대한 일부 의견을 생각한 후 "잠금 파일"의 부실을 확인하기 위해 코드를 편집했습니다. 내 시스템 에서이 기능을 수천 번 반복하면 바로 직전부터 평균 0.002066 ... 초가 발생했습니다.
lock = open('errloglock', 'w')
바로 다음에 :
remove('errloglock')
그래서 나는 부실을 나타내고 문제의 상황을 모니터링하기 위해 그 양의 5 배로 시작할 것이라고 생각했습니다.
또한 타이밍 작업을 할 때 실제로 필요하지 않은 약간의 코드가 있음을 깨달았습니다.
lock.close()
나는 열린 진술을 즉시 따랐 으므로이 편집에서 제거했습니다.
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:
블록 내의 모든 코드 는 스레드로부터 안전하므로 다른 프로세스가 파일에 액세스하기 전에 완료됩니다.
시나리오 그와 같다 : 사용자가 뭔가를 할 수있는 파일을 요청합니다. 그런 다음 사용자가 동일한 요청을 다시 보내면 첫 번째 요청이 완료 될 때까지 두 번째 요청이 완료되지 않았 음을 사용자에게 알립니다. 그래서 잠금 메커니즘을 사용 하여이 문제를 처리합니다.
내 작업 코드는 다음과 같습니다.
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
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