我试图在python 3x和linux/macOS中实现一个“记录管理器”类。这个类相对简单明了,我唯一想要的“困难”是能够在多个进程上访问同一个文件(保存结果的地方)。
从概念上讲,这似乎相当简单:保存时,获取文件的独占锁。更新您的信息,保存新信息,释放文件的独占锁。很简单。
我正在使用fcntl.lockf(file, fcntl.LOCK_EX)
获取独占锁。问题是,在互联网上,我发现很多不同网站的说这是不可靠的,它在windows上不起作用,NFS上的支持是不稳定的,macOS和linux之间的情况可能会发生变化。
我已经承认这些代码在windows上是行不通的,但我希望能够在macOS(单机)和linux(多台NFS服务器)上运行。
问题是,我似乎无法让它正常工作;经过一段时间的调试,在macOS上通过了测试之后,我在NFS上用linux(ubuntu 16.04)进行了测试,结果失败了。问题是由多个进程保存的信息之间不一致-某些进程缺少其修改,这意味着锁定和保存过程中出现问题。
我确信我做错了什么,我怀疑这可能与我在网上看到的问题有关。那么,如何处理通过NFS对macOS和linux上的同一文件的多重访问呢?
编辑
这就是将新信息写入磁盘的典型方法:
sf = open(self._save_file_path, 'rb+')
try:
fcntl.lockf(sf, fcntl.LOCK_EX) # acquire an exclusive lock - only one writer
self._raw_update(sf) #updates the records from file (other processes may have modified it)
self._saved_records[name] = new_info
self._raw_save() #does not check for locks (but does *not* release the lock on self._save_file_path)
finally:
sf.flush()
os.fsync(sf.fileno()) #forcing the OS to write to disk
sf.close() #release the lock and close
虽然这是一个典型的方法,它只从磁盘读取信息,看起来像:
sf = open(self._save_file_path, 'rb')
try:
fcntl.lockf(sf, fcntl.LOCK_SH) # acquire shared lock - multiple writers
self._raw_update(sf) #updates the records from file (other processes may have modified it)
return self._saved_records
finally:
sf.close() #release the lock and close
另外,这就是原始保存的样子:
def _raw_save(self):
#write to temp file first to avoid accidental corruption of information.
#os.replace is guaranteed to be an atomic operation in POSIX
with open('temp_file', 'wb') as p:
p.write(self._saved_records)
os.replace('temp_file', self._save_file_path) #pretty sure this does not release the lock
错误消息
我已经编写了一个单元测试,其中我创建了100个不同的进程,50个读取,50个写入同一个文件。每个进程都会进行一些随机等待,以避免按顺序访问文件。
问题是有些记录没有保存;最后有3-4个随机记录丢失,所以我只得到46-47个记录,而不是50个。
编辑2
我修改了上面的代码,获得的锁不是文件本身,而是一个单独的锁文件。这可以防止关闭文件会释放锁(如@janneb所建议的那样)的问题,并使代码在mac上正常工作。但是,同样的代码在带有NFS的linux上失败了。
目前没有回答
相关问题 更多 >
编程相关推荐