我需要锁定一个文件以便用 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”级。

我更喜欢的 锁文件 - 平台无关的文件锁定

锁定平台和设备特定的,但一般来说,你有一些选择:

  1. 使用flock(),或同等的(如果你的操作系统的支持)。这是咨询锁,除非你检查锁,其忽略。
  2. 使用一个带锁的副本移动解的方法,复制文件,写入新的数据,然后移动它(移动,不复制的移动是一个原子的运行在Linux-检查你的操作系统),并检查是否存在的锁的文件。
  3. 使用一个目录,作为一种"锁定"。这是必要的,如果你正在写NFS,由于NFS不支持flock().
  4. 还有可能使用共享存储器之间的进程,但我从来没有尝试过这一点;这是非常操作系统的具体。

所有这些方法中,只有使用旋锁定(试后失败)的技术,用于获取和测试了锁。这并留下一个很小的窗口mis-同步的,但它通常足够小到不是一个主要问题。

如果你是在寻找一个解决方案的交叉平台,那么你最好还是记录到另一个系统通过其他一些机构(一个最好的事情是NFS技术上文)。

注意到源码为受到同样的限制超过NFS,正常的文件,所以你不能写信给一个源码数据库网络共享,并得到同步。

我已经看了几种解决方案做到这一点,我的选择已 奥斯陆。并发

它是强有力和相对良好的记录。这是基于紧固件。

其他方案:

协调访问在操作系统级的单个文件充满了各种各样的问题,你可能不希望解决的问题。

您最好的选择是有坐标读取该文件/写访问一个单独的进程。

锁定文件通常是一个平台特定的操作,从而可能需要允许在不同的操作系统上运行的可能性。例如:

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
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top