- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我正在尝试在 python 3x 和 linux/macOS 中实现一个“记录管理器”类。该类(class)相对简单明了,我唯一想要的“困难”是能够在多个进程上访问同一个文件(保存结果的地方)。
从概念上讲,这似乎很简单:保存时,获取文件的独占锁。更新您的信息,保存新信息,释放文件的独占锁。很简单。
我正在使用 fcntl.lockf(file, fcntl.LOCK_EX)
获取独占锁。问题是,在互联网上,我发现 很多 不同的网站都在说这不可靠,它不能在 Windows 上运行,对 NFS 的支持不稳定,并且macOS 和 linux 之间可能会发生变化。
我已经接受该代码无法在 Windows 上运行,但我希望能够使其在 macOS(单机)和 Linux(在具有 NFS 的多台服务器上)上运行。
问题是我似乎无法完成这项工作;经过一段时间的调试并在 macOS 上通过测试后,一旦我在带有 linux (ubuntu 16.04) 的 NFS 上尝试它们,它们就失败了。问题是多个进程保存的信息不一致 - 一些进程缺少修改,这意味着锁定和保存过程出了问题。
我确定我做错了某事,我怀疑这可能与我在网上阅读的问题有关。那么,通过 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
此外,这就是 _raw_save 的样子:
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 上失败了。
最佳答案
我不明白文件锁和 os.replace() 的组合有何意义。当文件被替换(也就是目录项被替换)时,所有已经存在的文件锁(可能包括等待加锁成功的文件锁,这里的语义不太清楚)和文件描述符都会对旧文件,不是新文件。我怀疑这是导致您在测试中丢失一些记录的竞争条件背后的原因。
os.replace() 是一种很好的技术,可以确保读者不会阅读部分更新。但它在面对多个更新程序时并不能很好地工作(除非丢失一些更新是可以的)。
另一个问题是 fcntl 是一个非常非常愚蠢的 API。特别是,锁绑定(bind)到进程,而不是文件描述符。这意味着例如指向文件的任何文件描述符上的 close() 将释放锁定。
一种方法是使用“锁定文件”,例如利用 link() 的原子性。来自 http://man7.org/linux/man-pages/man2/open.2.html :
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 filesystem (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.
如果可以读取稍微陈旧的数据,那么您可以仅对更新文件时使用的临时文件使用此 link() 舞蹈,然后使用 os.replace() 用于读取的“主”文件(阅读然后可以是无锁的)。如果不是,那么您需要为“主”文件执行 link() 技巧,而忘记共享/独占锁定,所有锁都是独占的。
附录:使用锁定文件时要处理的一件棘手的事情是当进程由于某种原因终止并留下锁定文件时该怎么办。如果这是在无人值守的情况下运行,您可能需要合并某种超时和删除锁定文件(例如检查 stat() 时间戳)。
关于python - 如何在 NFS 上进行正确的文件锁定?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48770531/
这个问题已经有答案了: How to do case insensitive string comparison? (23 个回答) 已关闭 3 年前。 用户在我的输入栏中写入“足球”,然后执行第 6
啊,不习惯 javascript 中的字符串。 character_id= + id + correct= + correctOrIncorrect 这就是我需要制作成字符串的内容。如果您无法猜测字符
$(function() { var base_price = 0; CalculatePrice(); $(".math1").on('change', function(e) { Calc
我找不到任何文章回答问题:将Spinnaker部署到Spinnaker将管理的同一Kubernetes集群是否安全/正确?我主要是指生产,HA部署。 最佳答案 我认为Spinnaker和Kuberne
我正在使用MSVC在Windows上从源代码(官方源代码发布,而不是从仓库中)构建Qt5(Qt 5.15.0)。 我正在设置环境。变量,依赖项等,然后运行具有1600万个选项的configure,最后
我需要打印一个包含重复单词的数组。我的数组已经可以工作,但我不知道如何正确计算单词数。我已经知道,当我的索引计数器 (i) 为 49 时,并且当 (i) 想要计数到 50 时,我会收到错误,但我不知道
我正在遵循一个指南,该指南允许 Google map 屏幕根据屏幕尺寸禁用滚动。我唯一挣扎的部分是编写一个代码,当我手动调整屏幕大小时动态更改 True/False 值。 这是我按照说明操作的网站,但
我有一个类“FileButton”。它的目的是将文件链接到 JButton,FileButton 继承自 JButton。子类继承自此以使用链接到按钮的文件做有用的事情。 JingleCardButt
我的 friend 数组只返回一个数字而不是所有数字。 ($myfriends = 3) 应该是…… ($myfriends = 3 5 7 8 9 12). 如果我让它进入 while 循环……整个
这个问题在这里已经有了答案: Is there a workaround to make CSS classes with names that start with numbers valid?
我正在制作一个 JavaScript 函数,当调整窗口大小时,它会自动将 div 的大小调整为与窗口相同的宽度/高度。 该功能非常基本,但我注意到在调整窗口大小时出现明显的“绘制”滞后。在 JS fi
此问题的基本视觉效果可在 http://sevenx.de/demo/bootstrap-carousel/inc.carousel/tabbed-slider.html 获得。 - 如果你想看一看。
我明白,如果我想从函数返回一个字符串文字或一个数组,我应该将其声明为静态的,这样当被调用的函数被返回时,内容就不会“消亡”。 但我的问题是,当我在函数内部使用 malloc 分配内存时会怎样? 在下面
在 mySQL 数据库中存储 true/false/1/0 值最合适(读取数据消耗最少)的数据字段是什么? 我以前使用过一个字符长的 tinyint,但我不确定它是否是最佳解决方案? 谢谢! 最佳答案
我想一次读取并处理CSV文件第一行中的条目(例如打印)。我假设使用Unix风格的\n换行符,没有条目长度超过255个字符,并且(现在)在EOF之前有一个换行符。这意味着它是fgets()后跟strto
所以,我们都知道 -1 > 2u == true 的 C/C++ 有符号/无符号比较规则,并且我有一种情况,我想有效地实现“正确”比较。 我的问题是,考虑到人们熟悉的尽可能多的架构,哪种方法更有效。显
**摘要:**文章的标题看似自相矛盾。 本文分享自华为云社区《Java异常处理:如何写出“正确”但被编译器认为有语法错误的程序》,作者: Jerry Wang 。 文章的标题看似自相矛盾,然而我在“正
我有一个数据框,看起来像: dataDemo % mutate_each(funs(ifelse(. == '.', REF, as.character(.))), -POS) # POS REF
有人可以帮助我使用 VBScript 重新格式化/正确格式化带分隔符的文本文件吗? 我有一个文本文件 ^分界如下: AGREE^NAME^ADD1^ADD2^ADD3^ADD4^PCODE^BAL^A
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我是一名优秀的程序员,十分优秀!