Created
July 3, 2019 06:40
-
-
Save cevin/cd7bc4032d5082746f898b21709a56df to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// page: https://yuanxuxu.com/2018/11/26/php-snowflake/ | |
class Snowflake | |
{ | |
const EPOCH = 1543223810238; // 起始时间戳,毫秒 | |
const SEQUENCE_BITS = 12; //序号部分12位 | |
const SEQUENCE_MAX = -1 ^ (-1 << self::SEQUENCE_BITS); // 序号最大值 | |
const WORKER_BITS = 10; // 节点部分10位 | |
const WORKER_MAX = -1 ^ (-1 << self::WORKER_BITS); // 节点最大数值 | |
const TIME_SHIFT = self::WORKER_BITS + self::SEQUENCE_BITS; // 时间戳部分左偏移量 | |
const WORKER_SHIFT = self::SEQUENCE_BITS; // 节点部分左偏移量 | |
protected $timestamp; // 上次ID生成时间戳 | |
protected $workerId; // 节点ID | |
protected $sequence; // 序号 | |
protected $lock; // Swoole 互斥锁 | |
public function __construct($workerId) | |
{ | |
if ($workerId < 0 || $workerId > self::WORKER_MAX) { | |
trigger_error("Worker ID 超出范围"); | |
exit(0); | |
} | |
$this->timestamp = 0; | |
$this->workerId = $workerId; | |
$this->sequence = 0; | |
$this->lock = new swoole_lock(SWOOLE_MUTEX); | |
} | |
/** | |
* 生成ID | |
* @return int | |
*/ | |
public function getId() | |
{ | |
$this->lock->lock(); // 这里一定要记得加锁 | |
$now = $this->now(); | |
if ($this->timestamp == $now) { | |
$this->sequence++; | |
if ($this->sequence > self::SEQUENCE_MAX) { | |
// 当前毫秒内生成的序号已经超出最大范围,等待下一毫秒重新生成 | |
while ($now <= $this->timestamp) { | |
$now = $this->now(); | |
} | |
} | |
} else { | |
$this->sequence = 0; | |
} | |
$this->timestamp = $now; // 更新ID生时间戳 | |
$id = (($now - self::EPOCH) << self::TIME_SHIFT) | ($this->workerId << self::WORKER_SHIFT) | $this->sequence; | |
$this->lock->unlock(); //解锁 | |
return $id; | |
} | |
/** | |
* 获取当前毫秒 | |
* @return string | |
*/ | |
public function now() | |
{ | |
return sprintf("%.0f", microtime(true) * 1000); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment