可以使用相同的参数并行调用方法processReport
。但是,如果两个进程同时使用相同的$ reportId调用processReport
,则应该只进行一次处理。为了解决这个并发问题,我创建了辅助方法isLocked
,lock
和unlock
。 lock
为$ reportId创建临时文件。 isLocked
检查临时文件是否存在。如果文件存在则不应该进行处理。但问题是两个并行进程同时使用相同的$ reportId调用processReport
有时这个策略不起作用并且处理完成两次(这显然是因为使用文件系统太慢而发生)。由于进程不共享内存,我不知道如何解决这个并发问题。有没有办法避免两次处理相同的$ reportId?
private function getLockFileName($reportId) {
return sprintf('%s/%s.lock', sys_get_temp_dir(), $reportId);
}
private function isLocked($reportId) {
return file_exists($this->getLockFileName($reportId));
}
private function lock($reportId) {
touch($this->getLockFileName($reportId));
}
private function unlock($reportId) {
unlink($this->getLockFileName($reportId));
}
public function processReport($reportId) {
if ($this->isLocked($reportId)) return;
$this->lock($reportId);
// processing should be done only once for the same $reportId
$this->unlock($reportId);
}
答案 0 :(得分:2)
以下是“模拟”锁定的几种可能性
答案 1 :(得分:1)
semaphore extension是为这种情况而建的。例如:
public function processReport($reportId) {
$sem = sem_get("report-$reportId");
sem_aquire($sem); // Wait until the semaphore is free
// processing should be done only once for the same $reportId
sem_remove($sem); // Release for another request
}
您还可以使用APC或memcached将自己的快速锁写入共享内存。或者甚至更好地在第一次运行时将报告的结果写入共享内存,以便将来的请求更快地获得它。