php中睡眠100毫秒,PHP 毫秒级时间戳生成

做消息队列时发现在 Redis 的 ZSet 中,Score 数字只能设置到 17 位,我想让 Score 唯一,就尝试了几种时间戳 + 随机数的组合,于是得出一些答案

代码如下:

/**

* 取毫秒级时间戳,默认返回普通秒级时间戳 time() 及 3 位长度毫秒字符串

*

* @param int $msec_length 毫秒长度,默认 3

* @param int $random_length 添加随机数长度,默认 0

* @param bool $dot 随机是否存入小数点,默认 false

* @param int $delay 是否延迟,传入延迟秒数,默认 0

* @return string

*/

function msectime($msec_length = 3, $random_length = 0, $dot = false, $delay = 0) {

list($msec, $sec) = explode(' ', microtime());

$rand = $random_length > 0 ?

number_format(

mt_rand(1, (int)str_repeat('9', $random_length))

* (float)('0.' . str_repeat('0', $random_length - 1) . '1'),

$random_length,

'.',

'') : '';

$msectime = sprintf('%.0f', (floatval($msec) + floatval($sec) + $delay) * pow(10, $msec_length));

return $dot ? $msectime . '.' . substr($rand, 2) : $msectime . substr($rand, 2);

}

假设此刻调用上面的方法 msectime(7) 得到 15283761526669518

然后把这个数字扔进 Redis ZSet 的 Score 里,如下图,是正常的:

c1509b5ee6aba711ff210760fb0e5194.png

但是我们加一位,例如,变成了 152837615266695181

0b6e0851a76910a60cb29eca16ceab28.png

哦豁,变成了科学计数?Emmm,显然不合情理,这玩意儿似乎会丢掉精度呢。

怎么办?既然只能 17 位,我们就考虑减少时间戳的位数,当然毫秒级时间戳是非常精确的,先来看几个效果:

保留 3 位毫秒,即 10 位秒级时间戳 + 3 位毫秒。

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

echo msectime() . '

';

}

结果如下:(长图慎入)

ee07a0bd42ee8ada6a91c1a13fe33ab0.png

看起来有点意思,但是注意屁股 3 位数,这循环 100 次的结果,大部分数据都是一样的,当然这种情况,我们可以考虑在后面直接 mt_rand() 生成 5 4 位随机数拼接上

我考虑了一下这个,还是觉得不太保险,继续尝试加长毫秒位数,直接加两位看看

5 位毫秒

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

echo msectime(5) . '

';

}

结果如下:

8c31cbc82f51871c3b35cfa0668889b5.png

结果很好了!屁股两位的重复率很低!此时的数字长度为 15 位,似乎再生成两位随机数就可以了?

当然常规的随机数生成会考虑 mt_rand(10, 99) 这种形式

我建议这样生成:

function ex_mt_rand($length) {

$result = '';

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

$result .= mt_rand(0, 9);

}

return $result;

}

这样能得到更广的随机结果值,相比起普通的 mt_rand() 更可靠一些。

例如我们生成验证码之类,结果图参考:

8f7bce79d53cc4d10965dc7d84348d01.png

回到正题!既然也存在小部分重复值的情况,在我看来依靠随机数总是有风险的(当然没有位数限制,完全可以考虑扩大随机范围)

于是我直接把毫秒时间戳扩大到 17 位再看

7 位毫秒

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

echo msectime(7) . '

';

}

9cf184194258ede970c230dac078f679.png

惊喜的发现!完全没有重复值了,当然 Redis 里的 Score 长度被用光了,无法再随机哪怕 1 位数字

不过这个我的需求已经满足了!

以上方法是本人根据实际需求所写的一个,通过这个思路我们可以利用毫秒级时间戳生成订单号等需求。

再写一个例子:

msectime(3, 5, true);

// 得到结果如下

1528377789213.17053

1528377789213.19110

1528377789213.80717

1528377789213.12004

1528377789214.91335

1528377789214.08298

1528377789214.92701

1528377789214.85589

1528377789214.62383

欢迎大神提供更好的思路在秒杀等情况下生成不重复的数值。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值