我有一个通过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;
}
}
但我真的没有看到它的逻辑。
答案 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);
请注意,我没有测试过代码。