防止在Python中创建文件
我正在开发一个Python服务器,这个服务器可以同时处理多个数据库的事务,每个数据库存储着不同应用程序的性能数据。为了实现并发处理,我使用了Multiprocessing模块,这样每个事务线程都会在一个新的进程中启动,而共享内存的数据保护方案在这里不适用。
我选择使用sqlite作为我的数据库管理系统,并且决定把每个应用程序的数据库放在自己的文件里。不幸的是,这样做导致了数据库创建时的竞争条件;如果两个进程同时尝试为同一个新应用创建数据库,它们都会在同一个地方创建数据库文件。经过我的研究,我发现似乎无法在文件创建之前对其进行锁定;那么有没有其他方法可以确保文件不会被同时创建和写入呢?
提前感谢,
David
5 个回答
你可以在代码中尝试创建文件的时候捕捉到错误,然后在处理错误的地方检查一下这个文件是否已经存在。如果文件已经存在,就用这个现有的文件,而不是再去创建一个新的。
你可以使用 POSIX 的 O_EXCL
和 O_CREAT
标志来打开文件,这样可以确保只有一个进程能获取到这个文件,从而保证数据库的唯一性。不过,O_EXCL
在 NFSv2 或更早版本上是无法正常工作的,而且在其他网络文件系统上依赖它也不太可靠。
liblockfile
这个库实现了一种在网络文件系统上安全的锁定机制,具体内容可以在 open(2)
的手册中找到,这样会比较方便;不过我只看到有现成的 Ruby 和 Perl 的接口。如果你有这个需求,提供 Python 的接口可能会很有用,或者你也可以考虑自己重新实现这个算法:
O_EXCL Ensure that this call creates the file: if this flag is
specified in conjunction with O_CREAT, and pathname
already exists, then open() will fail. The behavior of
O_EXCL is undefined if O_CREAT is not specified.
When these two flags are specified, symbolic links are not
followed: if pathname is a symbolic link, then open()
fails regardless of where the symbolic link points to.
O_EXCL is only supported on NFS when using NFSv3 or later
on kernel 2.6 or later. In environments where NFS O_EXCL
support is not provided, programs that rely on it for
performing locking tasks will contain a race condition.
Portable programs that want to perform atomic file locking
using a lockfile, and need to avoid reliance on NFS
support for O_EXCL, can create a unique file on the same
file system (e.g., incorporating hostname and PID), and
use link(2) to make a link to the lockfile. If link(2)
returns 0, the lock is successful. Otherwise, use stat(2)
on the unique file to check if its link count has
increased to 2, in which case the lock is also successful.
在Unix系统中,处理普通文件的常见方法就是尝试创建这个文件,然后看看是否失败。在Python中,这样做的代码是:
try:
os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_EXCL)
except IOError: # or OSError?
# Someone else created it already.
至少,你可以用这种方法尝试创建一个“锁文件”,这个锁文件的名字和数据库的名字类似。如果锁文件成功创建了,那就可以继续创建数据库。如果没有创建成功,那就需要处理“数据库已经存在”的情况。