3

processReport可以使用相同的参数并行调用方法。processReport但是如果两个进程同时使用相同的 $reportId调用,则处理应该只进行一次。为了解决这个并发问题,我创建了辅助方法isLocked和. 为 $reportId 创建临时文件。检查临时文件是否存在。如果文件存在,则不应进行处理。但问题是两个并行进程同时调用相同的 $reportId 有时这种策略不起作用并且处理完成了两次(这显然是因为使用太慢的文件系统而发生的)。由于进程不共享内存,我不知道如何解决这个并发问题。有什么方法可以避免两次处理相同的 $reportId 吗?lockunlocklockisLockedprocessReport

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);
}
4

2 回答 2

2

这里有几种“模拟”锁的可能性

  1. - 你可以获取文件的排他锁,所以其他 php 进程将等待
  2. Memcached::cas - 基于 memcache 的锁,你需要组织 cas 循环
  3. sem_acquire - 如上所述,基于信号量的锁
  4. 共享内存- php 有共享内存模块
  5. 相同的会话 ID - 您可以使用相同的会话 ID,因为每个会话一次只允许一个请求
于 2013-10-09T20:07:51.850 回答
1

信号量扩展是为这种情况而构建的。例子:

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 将自己的快速锁写入共享内存。或者甚至更好地在第一次运行时将报告结果写入共享内存,以便将来的请求更快地得到它。

于 2013-10-09T18:02:29.760 回答