我们有 10 个 Linux 机器,每周必须运行 100 个不同的任务。当我们在家时,这些计算机主要在晚上执行这些任务。我的一位同事正在从事一个项目,通过使用 Python 自动启动任务来优化运行时间。他的程序将读取任务列表,抓取一个打开的任务,在文件中将该任务标记为正在进行中,然后一旦任务完成,就在文件中将任务标记为完成。任务文件将在我们的网络挂载上。
我们意识到不建议让一个程序的多个实例访问同一个文件,但我们真的看不到任何其他选择。当他在寻找一种防止两台计算机同时写入文件的方法时,我想出了一个自己的方法,这个方法似乎比我们在网上找到的方法更容易实现。我的方法是检查文件是否存在,如果不存在则等待几秒钟,如果存在则暂时移动文件。我写了一个脚本来测试这个方法:
#!/usr/bin/env python
import time, os, shutil
from shutil import move
from os import path
fh = "testfile"
fhtemp = "testfiletemp"
while os.path.exists(fh) == False:
time.sleep(3)
move(fh, fhtemp)
f = open(fhtemp, 'w')
line = raw_input("type something: ")
print "writing to file"
f.write(line)
raw_input("hit enter to close file.")
f.close()
move(fhtemp, fh)
在我们的测试中,这种方法奏效了,但我想知道我们是否会遇到一些使用这种方法没有发现的问题。我意识到两台计算机同时运行 exists() 可能会导致灾难。两台计算机不太可能同时到达那个点,因为任务在 20 分钟到 8 小时之间。
最佳答案
您基本上已经开发了二进制信号量(或互斥量)的文件系统版本。它是一个经过充分研究的用于锁定的结构,因此只要您获得正确的实现细节,它就应该可以工作。诀窍是让“测试和设置”操作,或者在你的情况下“检查存在和移动”,成为真正的原子。为此,我会使用这样的东西:
lock_acquired = False
while not lock_acquired:
try:
move(fh, fhtemp)
except:
sleep(3)
else:
lock_acquired = True
# do your writing
move(fhtemp, fh)
lock_acquired = False
您所拥有的程序大部分时间都可以运行,但如前所述,如果另一个进程在检查文件是否存在和调用 move
之间移动文件,您可能会遇到问题。我想你可以解决这个问题,但我个人建议坚持使用经过良好测试的互斥算法。 (我已经从 Andrew Tanenbaum 的 Modern Operating Systems 翻译/移植了上面的代码示例,但是我可能在转换中引入了错误 - 只是公平警告)
顺便说一下,Linux 上open
函数的手册页提供了这种文件锁定解决方案:
The solution for performing atomic file locking using a lockfile is to create a unique file on the same file system (e.g., incorporating hostname and pid), use link(2) to make a link to the lockfile. If link() 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.
要在 Python 中实现它,您可以这样做:
# each instance of the process should have a different filename here
process_lockfile = '/path/to/hostname.pid.lock'
# all processes should have the same filename here
global_lockfile = '/path/to/lockfile'
# create the file if necessary (only once, at the beginning of each process)
with open(process_lockfile, 'w') as f:
f.write('\n') # or maybe write the hostname and pid
# now, each time you have to lock the file:
lock_acquired = False
while not lock_acquired:
try:
link(process_lockfile, global_lockfile)
except:
lock_acquired = (stat(process_lockfile).st_nlinks == 2)
else:
lock_acquired = True
# do your writing
unlink(global_lockfile)
lock_acquired = False
关于python - 这种文件锁定方法是否可以接受?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3322011/