【发布时间】:2013-10-21 10:13:40
【问题描述】:
所以我有一个脚本用于接受和处理来自其他脚本和/或应用程序的请求。但是,我的脚本必须完成的任务之一是为每个请求分配一个唯一的、连续的“ID”。
例如,假设应用程序 A 向我的脚本发出 1000 个请求,同时应用程序 B 向我的脚本发出 500 个请求。我必须给他们 1500 个唯一的序列号,比如 2001~3500 给他们每个人。
但是它们之间的顺序无关紧要,所以我可以给它们这样的数字:
#2001 for 1st request from A (henceforth, A1)
#2002 for A2
#2003 for B1
#2004 for A3
#2005 for B2
...and so on...
我尝试创建一个存储该数字的文件和一个具有如下功能的单独锁定文件:
private function get_last_id()
{
// Check if lock file exists...
while (file_exists("LAST_ID_LOCKED")) {
// Wait a little bit before checking again
usleep(1000);
}
// Create the lock file
touch("LAST_ID_LOCKED");
// Create the ID file for the first time if required
if (!file_exists("LAST_ID_INDICATOR")) {
file_put_contents("LAST_ID_INDICATOR", 0);
}
// Get the last ID
$last_id = file_get_contents("LAST_ID_INDICATOR");
// Update the last ID
file_put_contents("LAST_ID_INDICATOR", $last_id + 1);
// Delete the lock file
unlink("LAST_ID_LOCKED");
return $last_id;
}
然而,这段代码会产生一个竞争条件,如果我向他们发送那些 1500 请求,最后一个 ID 将有很多缺失,(例如,只达到 3211 而不是 3500)。
我也尝试过像这样使用flock,但无济于事:
private function get_last_id()
{
$f = fopen("LAST_ID_INDICATOR", "rw");
while (true) {
if (flock($f, LOCK_SH)) {
$last_id = fread($f, 8192);
flock($f, LOCK_UN);
fclose($f);
break;
}
usleep($this->config["waiting_time"]);
}
$f = fopen("LAST_ID_INDICATOR", "rw");
while (true) {
if (flock($f, LOCK_SH)) {
$last_id = fread($f, 8192);
$last_id++;
ftruncate($f, 0);
fwrite($f, $last_id);
flock($f, LOCK_UN);
fclose($f);
break;
}
usleep($this->config["waiting_time"]);
}
return $last_id;
}
那么,我还能做些什么来为这种情况寻找解决方案?
注意事项:由于服务器限制,我仅限于 PHP 5.2,没有信号量之类的东西。
【问题讨论】:
-
你可以使用
uniqid()函数来生成id,它是基于microtime的。该文件的用途是什么? -
Uniqid 不会这样做,因为它是随机的,我需要数字是连续的。 LAST_ID_INDICATOR 的目的只是存储最后(最大)的 id 号。
-
,
uniqid()并不是那么随机,虽然不是顺序的,但每次调用函数都会按升序生成 id。使用hexdec()转换为十进制以了解我的意思。
标签: php concurrency race-condition