我有一个由 PHP 脚本维护的日志文件。PHP 脚本需要进行并行处理。我无法获得flock()
处理日志文件的机制:在我的情况下,flock()
不会阻止并行运行的 PHP 脚本共享的日志文件同时被访问并且有时被覆盖。
我希望能够读取文件,进行一些处理,修改数据并写回,而无需在服务器上并行运行相同的代码同时执行相同的操作。读修改写必须按顺序进行。
在我的一个共享主机(OVH France)上,它没有按预期工作。在这种情况下,我们看到计数器$c
在不同的 s 中具有相同的值,iframe
如果锁按预期工作,这应该是不可能的,它在其他共享主机上会这样做。
有什么建议可以使这项工作或替代方法吗?
谷歌搜索"read modify write" php
或fetch and add
没有test and set
提供有用的信息:所有解决方案都基于一个有效的flock()。
这是一些独立运行的演示代码来说明。它从浏览器向服务器生成多个并行请求并显示结果。很容易直观地观察到故障:如果您的网络服务器不像我的一个那样支持flock(),则计数器值和日志行数在某些帧中将是相同的。
<!DOCTYPE html>
<html lang="en">
<title>File lock test</title>
<style>
iframe {
width: 10em;
height: 300px;
}
</style>
<?php
$timeStart = microtime(true);
if ($_GET) { // iframe
// GET
$time = $_GET['time'] ?? 'no time';
$instance = $_GET['instance'] ?? 'no instance';
// open file
// $mode = 'w+'; // no read
// $mode = 'r+'; // does not create file, we have to lock file creation also
$mode = 'c+'; // read, write, create
$fhandle = fopen(__FILE__ .'.rwtestfile.txt', $mode) or exit('fopen');
// lock
flock($fhandle, LOCK_EX) or exit('flock');
// start of file (optional, only some modes like require it)
rewind($fhandle);
// read file (or default initial value if new file)
$fcontent = fread($fhandle, 10000) or ' 0';
// counter value from previous write is last integer value of file
$c = strrchr($fcontent, ' ') + 1;
// new line for file
$fcontent .= "<br />\n$time $instance $c";
// reset once in a while
if ($c > 20) {
$fcontent = ' 0'; // avoid long content
}
// simulate other activity
usleep(rand(1000, 2000));
// start of file
rewind($fhandle);
// write
fwrite($fhandle, $fcontent) or exit('fwrite');
// truncate (in unexpected case file is shorter now)
ftruncate($fhandle, ftell($fhandle)) or exit('ftruncate');
// close
fclose($fhandle) or exit('fclose');
// echo
echo "instance:$instance c:$c<br />";
echo $timeStart ."<br />";
echo microtime(true) - $timeStart ."<br />";
echo $fcontent ."<br />";
} else {
echo 'File lock test<br />';
// iframes that will be requested in parallel, to check flock
for ($i = 0; $i < 14; $i++) {
echo '<iframe src="?instance='. $i .'&time='. date('H:i:s') .'"></iframe>'."\n";
}
}
PHP 中有一个关于flock()
限制的警告:flock - Manual,但它是关于 ISAPI (Windows) 和 FAT (Windows)。我的服务器配置是:
PHP 版本 7.2.5
系统:Linux cluster026.gra.hosting.ovh.net
服务器 API:CGI/FastCGI