我们之前的id生成是直接用的php的uniqid
存在的问题有:
1. 高并发下容易重复:当高并发适用uniqid来产生唯一id的时候,我的测试数据是:1000并发,每并发产生1000次,实际输出63万uid(可能是标准输出原因未全部输出),5次重复
2. mysql中使用字符串类型的key存在性能问题
使用这里创建的ud_uniqid带来的改变:
优点1. 高并发重复几率降低:我的测试数据是:1000并发,每并发产生1000次,实际输出93万,无重复
优点2. 使用过程中,可以产生唯一的递增数值id,作为mysql主键有性能优势
缺点1. 性能比uniqid略低,耗时约为uniqid的1.5倍(不过在10e-5 -- 10e-4级别的时间差,1.5倍应该可以忽略)
缺点2. windows不能使用(windows不支持usleep)
缺点3. 由于使用了共享内存,所以需要在服务器开启的时候读取上一次的最大值,服务器关闭的时候写入当前的最大值
下面直接上代码了, 代码里面注释很清楚的:
<?php /** * functions: 产生64位唯一自增随机数,用于游戏唯一数值id生成 * 1. 数值分布:9位区号 3位服号 32位id号 10位随机码 10位随机码 * 2. 可提供范围:512区,每区8个游戏服务器,提供42亿id * 3. 重复性测试:100并发,每个并发进程产生1000次随机数,无重复 * 4. 性能测试:与系统自带uniqid函数相比,耗时为其1.5倍 * author: selfimpr * blog: http://blog.csdn.net/lgg201 * mail: lgg860911@yahoo.com.cn */ /** * 产生子进程 * $func_name: 子进程处理的过程函数 * 可接不定参数,为子进程过程函数需要的参数 */ 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; } } /** * 计数生成器 * 采用共享内存生成 * $key: 每个独立的$key标记为一个计数器 * $length: 分配内存大小 */ function counter($key = 0x1, $length = 256) { $segment_id = shmop_open($key, 'c', 0777, $length); $now = intval(shmop_read($segment_id, 0, shmop_size($segment_id))) + 1; shmop_write($segment_id, (string)$now, 0); shmop_close($segment_id); return $now; } /** * 自定义唯一id生成器 * $group_id: 区号 * $server_id: 服号 */ function ud_uniqid($group_id = 1, $server_id = 1) { $rand_key1 = rand(0, 1023); usleep(rand(0, 16)); $rand_key2 = rand(0, 1023); $id = counter(); return ($group_id << 55) | ($server_id << 52) | ($id << 20) | ($rand_key1 <=0) { if($f[$l] == $f[$l + 1]) echo $f[$l + 1]."\n"; $l --; } } /** * 生成uid并输出到标准输出 * $times: 产生次数 */ function check_repeat_out($times) { while($i ++ < $times) { echo ud_uniqid()."\n"; } } /** * 测试重复性(并发生成uid并输出到标准输出) * $concurrent: 并发数 * $times: 每个并发中产生uid次数 */ function test_repeat($concurrent, $times) { while($i ++ < $concurrent) { new_child(check_repeat_out, $times); } } /** * 与系统自带uniqid性能对比测试 * $times: 运行多少次进行时间比对 */ function test_performence($times) { $time = 0; while($i ++ < $times) { $start = microtime(true); ud_uniqid(); $end = microtime(true); $time += $end - $start; } echo "ud_uniqid($times): $time.\n"; $time = 0; $i = 0; while($i ++ repeat.check.dat * 3. 关闭test_repeat();方法(注释) * 4. 打开check_repeat('repeat.check.dat'); (测试时请注意文件路径),运行:php ud_uniqid.php,如果不产生输出,则标明无重复 * 性能测试: * 打开test_performence(); CLI模式运行即可 */ //test_performence(10000); //test_repeat(100, 1000); //check_repeat('repeat.check.dat'); ?>
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。