我如何处理"竞争条件"计划在每分钟运行的脚本实例之间,为目录中的每个文件执行以下任务:
由于流程每1分钟运行一次,因此2个实例可能会重叠并处理相同的文件。我可以通过文件锁定和跳过已打开的文件来防止这种情况,但问题仍然存在:
进程A接受inputA.jpg并找到下一个可用的文件名image_01。
进程B接受inputB.jpg并找到下一个可用的文件名image_01。
所以混乱开始......
不幸的是,我无法在SQL表中插入任何占位符记录来显示正在处理下一个文件名。
循环的伪代码:
foreach ($file)
{
$name = findFileNameInSql($file)
$path1 = createFile($name, $settings1);
$path2 = createFile($name, $settings2);
$path3 = createFile($name, $settings3);
addToSql($file, $name, $path1, $path2, $path3)
}
实际代码有点复杂,包括文件修改和2个SQL表的事务插入。如果createFile()
失败,应用程序将回滚所有先前创建的文件。当一个app实例正在创建文件时,它显然会产生问题" abc"和第二个实例有错误的文件" abc"已经存在。
编辑:
当然,限制脚本只有一个实例可能是解决方案,但我希望找到一种方法来并行运行它们。如果没有办法,我们可以将其作为副本关闭。
答案 0 :(得分:0)
您需要生成从数据库中的数据库原子返回下一个可用文件名的代码,以便数据库不能返回相同的文件名两次。这本身就是一个数据库问题,而不是一个perl问题。
您不会说出您正在使用的数据库,但有几种方法可以解决这个问题。 在MySQL中执行它的一种天真和野蛮的方法是让perl脚本在表上使用文件名执行LOCK TABLE表WRITE,同时计算新的并执行其工作。使用新文件名更新表后,您可以释放锁。表锁虽然不能很好地处理交易。
或者你可以做一些更优雅的事情,比如在数据库本身中实现具有适当锁定的存储过程以返回新文件名。
或者使用AUTOINCREMENT列,这样每次向表中添加内容时,都会得到一个新数字(因而是一个新文件名)。
但这一切都变得相当复杂;如果您同时拥有多个事务,数据库如何解析这些事务通常是可配置的事情,所以我无法告诉您将会发生什么。
鉴于您的代码主要是在重新组织磁盘上的数据,但同时运行多个作业并没有多大优势;无论如何,这段代码可能都是I / O绑定的。在这种情况下,只是为了使代码更改更简单,其他人建议一次只运行一个副本。