我们有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小时之间。在
在我看来,如果你改变了数据结构,要完成一些简单的事情,你付出了太多的努力。现在您有一个包含任务列表的文件。在
不如把任务队列改为一个目录,其中每个挂起的任务都是一个文件?然后,这个过程就像从“Pending”目录中选择一个任务一样简单,将其移动到目录(比如“Running”),完成后,将任务文件移动到“Completed”目录。因为文件移动是原子操作,所以不会有争用条件(如果移动失败,意味着另一个工作人员刚刚抢占了它,所以选择下一个任务)。在
另外,检查进度就像在其中一个目录上发出
ls
一样简单您基本上已经开发了二进制信号量(或互斥体)的文件系统版本。它是一个经过充分研究的用于锁定的结构,因此只要您正确地掌握了实现细节,它就应该可以工作。诀窍是让“测试并设置”操作,或者在您的例子中是“检查存在并移动”,使之成为真正的原子。为此,我会用这样的方法:
这个程序在大部分时间内都可以正常工作,但是正如前面提到的,如果另一个进程在检查文件是否存在和调用
move
之间移动文件,则可能会出现问题。我想您可以解决这个问题,但我个人建议您坚持使用经过良好测试的互斥体算法。(我已经翻译/移植了Andrew Tanenbaum的现代操作系统中的上述代码示例,但有可能我在转换过程中引入了错误-只是警告一下)顺便说一下,Linux上
open
函数的手册页提供了以下文件锁定解决方案:要在Python中实现这一点,可以执行以下操作:
^{2}$如果您不跟踪您的
move
调用,看看它们是否成功,您将永远不知道您是否成为定时窗口的牺牲品。请记住,如果有什么地方出了问题,它会在最坏的情况下,。在与其使用文件的内容作为标志,不如使用文件名本身?对于每个任务,将文件“task_waiting_to \u run”重命名为“task_running”为“task_complete”。如果从“task_waiting_to_run”重命名为“task_running”失败,则意味着另一个框首先到达那里。在
相关问题 更多 >
编程相关推荐