Мне нужно заблокировать файл для записи на Python. Доступ к нему будет осуществляться из нескольких процессов Python одновременно. Я нашел несколько решений в Интернете, но большинство из них не подходят для моих целей, поскольку часто они основаны только на Unix или Windows.
with FileLock("myfile.txt.lock"): # work with the file as it is now locked print("Lock acquired.")
Ответ 2
Другие решения ссылаются на множество внешних баз кода. Если вы предпочитаете сделать это самостоятельно, вот некоторый код для кроссплатформенного решения, которое использует соответствующие инструменты блокировки файлов в системах 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 deflock_file(f): if f.writable(): fcntl.lockf(f, fcntl.LOCK_EX) defunlock_file(f): if f.writable(): fcntl.lockf(f, fcntl.LOCK_UN) except ModuleNotFoundError: # Windows file locking import msvcrt, os deffile_size(f): return os.path.getsize( os.path.realpath(f.name) ) deflock_file(f): msvcrt.locking(f.fileno(), msvcrt.LK_RLCK, file_size(f)) defunlock_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. classAtomicOpen: # 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): returnFalse else: returnTrue
Теперь, AtomicOpen может использоваться в with блоке, где обычно используется open оператор.
ПРЕДУПРЕЖДЕНИЯ:
Если запуск в Windows и Python завершается сбоем перед вызовом exit, я не уверен, каким будет поведение блокировки.
Представленная здесь блокировка носит рекомендательный, а не абсолютный характер. Все потенциально конкурирующие процессы должны использовать класс "AtomicOpen".
По состоянию на (9 ноября 2020 г.) этот код блокирует только доступные для записи файлы в системах Posix. В какой-то момент после публикации и до этой даты стало незаконным использовать fcntl.lock для файлов, доступных только для чтения.
Ответ 3
There is a cross-platform file locking module here: Portalocker
Although as Kevin says, writing to a file from multiple processes at once is something you want to avoid if at all possible.
If you can shoehorn your problem into a database, you could use SQLite. It supports concurrent access and handles its own locking.
Ответ 4
I have been looking at several solutions to do that and my choice has been oslo.concurrency
It's powerful and relatively well documented. It's based on fasteners.
Other solutions:
Portalocker: requires pywin32, which is an exe installation, so not possible via pip