PHP防止同时执行函数(通过PHP限制限制)

时间:2013-02-27 20:09:05

标签: php multithreading concurrency call throttling

我有一个通过CURL将HTTP请求发送到www.server.com的功能

我的任务是确保www.server.com每2秒获得一次请求。

可能的解决方案:

创建一个函数checktime(),它将当前的调用时间存储在数据库中,并在每次调用时检查数据库并使系统暂停2秒钟:

$oldTime = $this->getTimeFromDatabase();
if ($oldTime < (time() - 2) ) { // if its been 2 seconds
  $this->setNewTimeInDatabase(); 
  return true;
} else {
  sleep(2);
  return false;
}

问题/疑问:

可以说,最后一次请求www.server.com的请求是1361951000.然后其他10个用户尝试在1361951001(1秒后)上做请求。 checktime()将调用函数。

由于它只有1秒,因此该函数将返回false。所有10个用户将等待2秒。这是否意味着在1361951003上会同时发送10个请求?由于checktime()中错误调用$ this-&gt; setNewTimeInDatabase(),是否有可能在数据库中不会更改上次请求的时间?

谢谢!

更新

我刚刚被告知使用循环可以解决问题:

for($i=0;$i<300;$i++)
{
   $oldTime = $this->getTimeFromDatabase();
   if ($oldTime < (time() - 2) ) { // if its been 2 seconds
   $this->setNewTimeInDatabase(); 
   return true;
   } else {
    sleep(2);
    return false;
   }
}

但我真的没有看到它的逻辑。

2 个答案:

答案 0 :(得分:2)

我认为你需要一些semaphore的实现。数据库可以工作,只要您可以保证只有一个线程可以写入数据库然后发出请求。

例如,您可以对数据库使用更新请求,然后检查更新的行(以检查更新是否实际发生)。如果更新成功,您可以假设您获得了互斥锁,然后发出请求(假设时间是正确的)。像这样:

$oldTime = $this->getTimeFromDatabase();
if ($oldTime < (time() - 2) && $this->getLock()) { // if its been 2 seconds
  $this->setNewTimeInDatabase(); 
  $this->releaseLock();
  return true;
} else {
  sleep(2);
  return false;
}  

function getLock()
{
    return $mysqli->query('UPDATE locktable set locked = 1 WHERE locked = 0');
}

function releaseLock()
{
     $mysqli->query('UPDATE locktable set locked = 0');
}

我不确定mysql函数,但我相信可以得到一般的想法。

答案 1 :(得分:1)

注意使用数据库。例如,MySQL并不总是100%与其会话同步,因此出于锁定目的而依赖它是不安全的。

您可以通过方法flock使用文件锁定,在那里您可以节省访问时间。然后您可以确保锁定文件,因此没有两个或更多进程可以访问它同一时间。

它可能会是这样的:

$filepath = "lockfile_for_source";
touch($filepath);
$fp = fopen("lockfile_for_resource", "r") or die("Could not open file.");

while(true){
  while(!flock($fp, LOCK_EX)){
    sleep(0.25); //wait to get file-lock.
  }

  $time = file_get_contents($filepath);
  $diff = time() - $time;
  if ($diff >= 2){
    break;
  }else{
    flock($fp, LOCK_UN);
  }
}

//Following code would never be executed simultaneously by two scripts.
//You should access and use your resource here.

fwrite($fp, time());
fflush($fp);
flock($fp, LOCK_UN); //remove lock on file.
fclose($fp);

请注意,我没有测试过代码。