题
我需要锁定一个文件以便用 Python 写入。它将同时从多个 Python 进程访问。我在网上找到了一些解决方案,但大多数都无法达到我的目的,因为它们通常仅基于 Unix 或基于 Windows。
解决方案
好吧,所以我最终使用了我编写的代码 在这里,在我的网站上 链接已失效,请在 archive.org 上查看 (也可以在 GitHub 上找到)。我可以按以下方式使用它:
from filelock import FileLock
with FileLock("myfile.txt"):
# work with the file as it is now locked
print("Lock acquired.")
其他提示
有是一种跨平台文件锁定模块这里: Portalocker
虽然凯文说,写从多个进程文件一次是你想避免,如果在所有可能的东西。
如果你能鞋拔子您的问题到数据库中,你可以使用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”级。
我更喜欢的 锁文件 强> - 平台无关的文件锁定
锁定平台和设备特定的,但一般来说,你有一些选择:
- 使用flock(),或同等的(如果你的操作系统的支持)。这是咨询锁,除非你检查锁,其忽略。
- 使用一个带锁的副本移动解的方法,复制文件,写入新的数据,然后移动它(移动,不复制的移动是一个原子的运行在Linux-检查你的操作系统),并检查是否存在的锁的文件。
- 使用一个目录,作为一种"锁定"。这是必要的,如果你正在写NFS,由于NFS不支持flock().
- 还有可能使用共享存储器之间的进程,但我从来没有尝试过这一点;这是非常操作系统的具体。
所有这些方法中,只有使用旋锁定(试后失败)的技术,用于获取和测试了锁。这并留下一个很小的窗口mis-同步的,但它通常足够小到不是一个主要问题。
如果你是在寻找一个解决方案的交叉平台,那么你最好还是记录到另一个系统通过其他一些机构(一个最好的事情是NFS技术上文)。
注意到源码为受到同样的限制超过NFS,正常的文件,所以你不能写信给一个源码数据库网络共享,并得到同步。
我已经看了几种解决方案做到这一点,我的选择已 奥斯陆。并发
它是强有力和相对良好的记录。这是基于紧固件。
其他方案:
- Portalocker:需要pywin32,这是一个可执行软件安装,所以不可能通过pip
- 紧固件:很差的记录
- 文件锁:弃用
- flufl.锁定:NFS安全的文件锁定为POSIX系统。
- simpleflock :最后更新2013-07
- zc。文件锁 :最后更新2016-06(作为2017-03)
- lock_file :最后更新于2007年10期
协调访问在操作系统级的单个文件充满了各种各样的问题,你可能不希望解决的问题。
您最好的选择是有坐标读取该文件/写访问一个单独的进程。
锁定文件通常是一个平台特定的操作,从而可能需要允许在不同的操作系统上运行的可能性。例如:
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()
我已经紧随公开声明,所以我在此编辑删除它。
的方案强>是这样的: 用户请求一个文件做一些事情。然后,如果用户再次发送同样的请求时,它通知用户该第二请求未完成,直到第一请求完成。这就是为什么,我用锁的机制来处理这个问题。
下面是我的工作的代码:
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
我找到一个简单的工作和(!) 执行情况 从头发花白的-蟒蛇。
简单的使用操作系统。打开(...,文件)+操作系统。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