php 函数 慢,PHP uniqid函数执行缓慢的问题

php 函数 慢,PHP uniqid函数执行缓慢的问题前段时间某个需求:客户提交简单的表单可以创建一个适应于全终端(PC,Pad,Phone)的刮刮卡活动H5页面,其中涉及到客户可在线生成限额6W奖品码的功能。因为需要保持每个活动奖品码的唯一,我们先是准备用PHP的uniqid函数来生成UUID(UniversallyUniqueIDentifier,也叫GUID,为全局唯一标识符,是一种由算法生成的唯一标识)来生成。但当我们用生成1W测试时候,…

前段时间某个需求:客户提交简单的表单可以创建一个适应于全终端(PC,Pad,Phone)的刮刮卡活动H5页面,其中涉及到客户可在线生成限额6W奖品码的功能。

因为需要保持每个活动奖品码的唯一,我们先是准备用PHP的uniqid函数来生成UUID(Universally Unique IDentifier,也叫GUID,为全局唯一标识符,是一种由算法生成的唯一标识)来生成。

但当我们用生成1W测试时候,发现生成过些需要几十秒,还不包括插入至数据库的时间,然后用xhprof写了个简单例子进行性能测试 <?php

xhprof_enable(XHPROF_FLAGS_CPU|XHPROF_FLAGS_MEMORY);

function myfunc(){

for($i=0;$i<10000;$i++){

$data = uniqid();

}

}

myfunc();

$data = xhprof_disable();

print_r($data);

测试结果:[myfunc==>uniqid] => Array(

[ct] => 10000

[wt] => 39975062

[cpu] => 0

[mu] => 960752

[pmu] => 0

)

竟然需要接近40秒的时间生成,单次执行需要3969微秒,也即是0.003969秒生成。如果用户提交表单的同时生成兑换码,最坏情况下需要4分钟才给用户反应,当然可以用消息队列异步生成,但是为啥uniqid需要如此多的时间来生成一个简单的字符串呢?

然后去查看uniqid的实现源码,代码贴在下面PHP_FUNCTION(uniqid)

{

char *prefix = “”;

#if defined(__CYGWIN__)

zend_bool more_entropy = 1;

#else

zend_bool more_entropy = 0;

#endif

char *uniqid;

int sec, usec, prefix_len = 0;

struct timeval tv;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, “|sb”, &prefix, &prefix_len,

&more_entropy)) {

return;

}

#if HAVE_USLEEP && !defined(PHP_WIN32)

if (!more_entropy) {

#if defined(__CYGWIN__)

php_error_docref(NULL TSRMLS_CC, E_WARNING, “You must use ‘more entropy’ under CYGWIN”);

RETURN_FALSE;

#else

usleep(1);

#endif

}

#endif

gettimeofday((struct timeval *) &tv, (struct timezone *) NULL);

sec = (int) tv.tv_sec;

usec = (int) (tv.tv_usec % 0x100000);

/* The max value usec can have is 0xF423F, so we use only five hex

* digits for usecs.

*/

if (more_entropy) {

spprintf(&uniqid, 0, “%s%08x%05x%.8F”, prefix, sec, usec, php_combined_lcg(TSRMLS_C) * 10);

} else {

spprintf(&uniqid, 0, “%s%08x%05x”, prefix, sec, usec);

}

RETURN_STRING(uniqid, 0);

}

看逻辑也没有复杂的操作,也是对现在时间秒和微秒进行简单的处理,然后写了个简单的测试int getUniqid( char * uid) {

int sec, usec;

struct timeval tv;

gettimeofday(( struct timeval *) &tv, ( struct timezone *) NULL);

sec = ( int) tv. tv_sec;

usec = ( int ) (tv.tv_usec % 0x100000);

sprintf(uid, “%08x%05x” , sec, usec);

return 1;

}

执行1W次也就需要2000微秒,这又是为啥?但是我们发现生成的uid中存在大量的重复,这是才注意点原代码中的usleep函数,

加上usleep函数在测试,这次和PHP结果一致也需要将近40秒,usleep在此为了保持每次生成的uid不同。

那问题出现在usleep函数上了,然后在usleep前后加上取间隔时间,代码如下struct timeval start, end;

gettimeofday(( struct timeval *) &start, ( struct timezone *) NULL);

usleep(1);

gettimeofday(( struct timeval *) &end, ( struct timezone *) NULL);

unsigned long space = (end.tv_sec – start. tv_sec) * 1000000 + end.tv_usec

– start. tv_usec;

spaceCost += space;

最后发现生成1W奖品码需要39.99587739.995877秒,而usleep间隔时间总和39.982442m,通过打印usleep时间发现每次usleep(1)从进程挂起到唤醒需要4000微秒,本来就知道usleep达不到精度,也也相差太远了点。

最后用了下面代码生成奖品码/**

* 生成兑换码并保存到数据库 返回setNo

* $pageId 活动ID

* $level 奖品等级

* $numbers 生成奖品的个数

*/

public static function generateCDKEYAndSave($pageId,$level,$numbers){

$level1Prefix =array(2,5,9,’E’,’F’,’M’,’N’,’Q’,’K’,’Z’);//一等奖的前缀

$level2Prefix =array(1,3,7,’A’,’C’,’J’,’R’,’U’,’V’,’X’);//二等奖的前置

$level3Prefix = array(4,6,8,’B’,’D’,’G’,’H’,’I’,’L’,’O’,’P’,’R’,’S’,’T’,’W’,’Y’);//三等奖的前缀

if(empty($pageId) || empty($level) || empty($numbers)) return false;

$levelPrefix =$level1Prefix;

if($level==2) $levelPrefix = $level2Prefix;

if($level==3) $levelPrefix = $level3Prefix;

$codes =array();

$now = time();

for($i=0;$i

$prefixKey = array_rand($levelPrefix);

$prefix = self::COUPON_PREFIX.$levelPrefix[$prefixKey];

//$code =base_convert(hexdec(md5(uniqid())),10,26); 服务器上面uniqid执行慢的要死

//$code =base_convert(hexdec(md5($pageId.’A#1$v&’.$i)),10,26);//数据过多 hexdec丢失大量精度

$code1 = base_convert(substr(md5($pageId.$i.$now), 0, 10), 16, 36);

$code2 = base_convert($i, 10, 26);

$code2Len = strlen($code2);

if ($code2Len == 1) {

$code2 .= chr(rand(82, 90)) . chr(rand(82, 90)) . chr(rand(82, 90));

}

else if ($code2Len == 2) {

$code2 .= chr(rand(82, 90)) . chr(rand(82, 90));

}

else if ($code2Len == 3) {

$code2 .= chr(rand(82, 90));

}

$code =$code1.$code2;

$codes[] = $prefix.strtoupper($code);

}

return $codes;

}

附带uuid测试代码#include

#include

#include

#include

unsigned long sleepCost = 0;

int getUniqid( char * uid,int times) {

struct timeval start, end;

gettimeofday(( struct timeval *) &start, ( struct timezone *) NULL);

usleep(1);

gettimeofday(( struct timeval *) &end, ( struct timezone *) NULL);

unsigned long space = (end.tv_sec – start. tv_sec) * 1000000 + end.tv_usec

– start. tv_usec;

sleepCost += space;

if (0 == times%1000) printf (“\n—–sleep cost——-\n%lu usec\n”, space);

int sec, usec;

struct timeval tv;

gettimeofday(( struct timeval *) &tv, ( struct timezone *) NULL);

sec = ( int) tv. tv_sec;

usec = ( int ) (tv.tv_usec % 0x100000);

sprintf(uid, “%08x%05x” , sec, usec);

return 1;

}

int main( int argc, char * argv[]) {

struct timeval start, end;

gettimeofday(( struct timeval *) &start, ( struct timezone *) NULL);

for ( int i = 1; i <= 10000; i++) {

char data[20];

getUniqid(data,i);

}

gettimeofday(( struct timeval *) &end, ( struct timezone *) NULL);

unsigned long space = (end.tv_sec – start. tv_sec) * 1000000 + end.tv_usec

– start. tv_usec;

printf( “\n—–cost——-\n% lu usec\n \n—–sum sleep sost——-\n% lu usec\n” , space,sleepCost);

}

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

今天的文章php 函数 慢,PHP uniqid函数执行缓慢的问题分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/9868.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注