PHP-PHP中的uniqid在高并发下的重复问题
项目是一个高并发的web项目,并且会有后台进程(pcntl并发),两者都会利用uniqid去生成唯一id,今天发现一个bug,在高并发情况下,uniqid可能产生重复输出
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
项目是一个高并发的web项目,并且会有后台进程(pcntl并发),两者都会利用uniqid去生成唯一id,今天发现一个bug,在高并发情况下,uniqid可能产生重复输出
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(6)
以下是测试代码:
<?php
function new_child($func_name) {
$args = func_get_args();
unset($args[0]);
$pid = pcntl_fork();
if($pid == 0) {
function_exists($func_name) and exit(call_user_func_array($func_name, $args)) or exit(-1);
} else if($pid == -1) {
echo "Couldn’t create child process.";
} else {
return $pid;
}
}
function generate() {
$t = array();
while($i ++ < 10) {
$uid = uniqid(true)."/n";
array_push($t, $uid);
}
sort($t);
while(-- $i >=0) {
echo array_shift($t);
}
}
while($i ++ < 1000) {
new_child(generate);
}
?>
测试方法: 命令行运行此程序,重定向输出到文件,然后利用下面程序检查重复:
<?php
$f = file("tttttt");
$f = array_count_values($f);
foreach($f as $k => $c) if($c > 1) echo $c.'_'.$k;
?>
解决方法: 我们现在是在uniqid后又加了rand(1, 10000),在1000并发,每进程10次uniqid的情况下,再没有产生重复。
md5($_SERVER['HTTP_USER_AGENT'].gettimeofday(true).lcg_value())
这样的方式应该可以解决重复和并发问题。
uniqid() 函数本身就是基于以微秒计的当前时间,所以在高并发的情况下肯定会出现重复的情况,解决的的方法是你可以在这个前提下再生成一个随机数,然后两者结合后产生出一个新的数,这样就会降低重复的概率。如果还是想要再精确的话还可以加上客户端的IP的Md5码来一同生成,这样应该重复的概率就极低了,可以说是几乎不会重复。
<?php
function getRand(){
return uniqid() . rand(1, 100000);
}
echo getRand();
exit;
?>
降低重复率 确实 是好方法,速度也足够快。
完全不会重复,有一个方法,但高并发的IO确实是个问题,可以用memcache,代码很简单
$id = null;
while($id==null)
{
$id = uniqid();
$row = ClassMemcache::Init()->get("tbl_news_{$id}");
if($row)
{
$id = null;
}
}
uniqid 并不支持并发。即使你加上了rand,理论上还是会出现重复。
uniqid(prefix,more_entropy)
prefix 可选。为 ID 规定前缀。如果两个脚本在相同的微妙生成 ID,该参数很有用。
more_entropy 可选。规定位于返回值末尾的更多的熵。
如果 prefix 参数为空,则返回的字符串有 13 个字符串长。如果 more_entropy 参数设置为 true,则是 23 个字符串长。
如果 more_entropy 参数设置为 true,则在返回值的末尾添加额外的熵(使用组合线形同余数生成程序),这样可以结果的唯一性更好。
uniqid(rand(1, 100000)); 这个可以在开头加 但是位数不一样
uniqid('',true); 这样可以末尾添加额外的熵