PHP使用SnowFlake算法生成唯一ID

来源:互联网 发布:linux shell 参数 编辑:程序博客网 时间:2024/05/17 07:18
namespace App\Services;abstract class Particle {    const EPOCH = 1479533469598;    const max12bit = 4095;    const max41bit = 1099511627775;    static $machineId = null;    public static function machineId($mId = 0) {        self::$machineId = $mId;    }    public static function generateParticle() {        /*        * Time - 42 bits        */        $time = floor(microtime(true) * 1000);        /*        * Substract custom epoch from current time        */        $time -= self::EPOCH;        /*        * Create a base and add time to it        */        $base = decbin(self::max41bit + $time);        /*        * Configured machine id - 10 bits - up to 1024 machines        */        if(!self::$machineId) {            $machineid = self::$machineId;        } else {            $machineid = str_pad(decbin(self::$machineId), 10, "0", STR_PAD_LEFT);        }        /*        * sequence number - 12 bits - up to 4096 random numbers per machine        */        $random = str_pad(decbin(mt_rand(0, self::max12bit)), 12, "0", STR_PAD_LEFT);        /*        * Pack        */        $base = $base.$machineid.$random;        /*        * Return unique time id no        */        return bindec($base);    }    public static function timeFromParticle($particle) {        /*        * Return time        */        return bindec(substr(decbin($particle),0,41)) - self::max41bit + self::EPOCH;    }}

调用方法如下

Particle::generateParticle($machineId);//生成IDParticle::timeFromParticle($particle);//反向计算时间戳

以上for 5000+重复率为5%,效率比较高。

以下for100000次重复率0,效率低。

class IdWork{    //开始时间,固定一个小于当前时间的毫秒数即可    const twepoch =  1474992000000;//2016/9/28 0:0:0    //机器标识占的位数    const workerIdBits = 5;    //数据中心标识占的位数    const datacenterIdBits = 5;    //毫秒内自增数点的位数    const sequenceBits = 12;    protected $workId = 0;    protected $datacenterId = 0;    static $lastTimestamp = -1;    static $sequence = 0;    function __construct($workId=0, $datacenterId=0){        //机器ID范围判断        $maxWorkerId = -1 ^ (-1 << self::workerIdBits);        if($workId > $maxWorkerId || $workId< 0){            throw new Exception("workerId can't be greater than ".$this->maxWorkerId." or less than 0");        }        //数据中心ID范围判断        $maxDatacenterId = -1 ^ (-1 << self::datacenterIdBits);        if ($datacenterId > $maxDatacenterId || $datacenterId < 0) {            throw new Exception("datacenter Id can't be greater than ".$maxDatacenterId." or less than 0");        }        //赋值        $this->workId = $workId;        $this->datacenterId = $datacenterId;    }    //生成一个ID    public function nextId(){        $timestamp = $this->timeGen();        $lastTimestamp = self::$lastTimestamp;        //判断时钟是否正常        if ($timestamp < $lastTimestamp) {            throw new Exception("Clock moved backwards.  Refusing to generate id for %d milliseconds", ($lastTimestamp - $timestamp));        }        //生成唯一序列        if ($lastTimestamp == $timestamp) {            $sequenceMask = -1 ^ (-1 << self::sequenceBits);            self::$sequence = (self::$sequence + 1) & $sequenceMask;            if (self::$sequence == 0) {                $timestamp = $this->tilNextMillis($lastTimestamp);            }        } else {            self::$sequence = 0;        }        self::$lastTimestamp = $timestamp;        //        //时间毫秒/数据中心ID/机器ID,要左移的位数        $timestampLeftShift = self::sequenceBits + self::workerIdBits + self::datacenterIdBits;        $datacenterIdShift = self::sequenceBits + self::workerIdBits;        $workerIdShift = self::sequenceBits;        //组合4段数据返回: 时间戳.数据标识.工作机器.序列        $nextId = (($timestamp - self::twepoch) << $timestampLeftShift) |            ($this->datacenterId << $datacenterIdShift) |            ($this->workId << $workerIdShift) | self::$sequence;        return $nextId;    }    //取当前时间毫秒    protected function timeGen(){        $timestramp = (float)sprintf("%.0f", microtime(true) * 1000);        return  $timestramp;    }    //取下一毫秒    protected function tilNextMillis($lastTimestamp) {        $timestamp = $this->timeGen();        while ($timestamp <= $lastTimestamp) {            $timestamp = $this->timeGen();        }        return $timestamp;    }}
0 0
原创粉丝点击