You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

68 lines
2.1 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package tools
import (
"sync"
"time"
)
const (
epoch = int64(1577808000000) // 设置起始时间(时间戳/毫秒)2020-01-01 00:00:00有效期69年
timestampBits = uint(41) // 时间戳占用位数
datacenteridBits = uint(5) // 数据中心id所占位数
workeridBits = uint(5) // 机器id所占位数
sequenceBits = uint(12) // 序列所占的位数
timestampMax = int64(-1 ^ (-1 << timestampBits)) // 时间戳最大值
sequenceMask = int64(-1 ^ (-1 << sequenceBits)) // 支持的最大序列id数量
workeridShift = sequenceBits // 机器id左移位数
datacenteridShift = sequenceBits + workeridBits // 数据中心id左移位数
timestampShift = sequenceBits + workeridBits + datacenteridBits // 时间戳左移位数
)
type snowflake struct {
sync.Mutex
timestamp int64
workerid int64
datacenterid int64
sequence int64
}
var s = &snowflake{
timestamp: 0,
datacenterid: 1,
workerid: 2,
sequence: 0,
}
func SnowflakeId() int64 {
return s.nextVal()
}
// nextVal 返回下一个Snowflake ID
func (s *snowflake) nextVal() int64 {
s.Lock()
now := time.Now().UnixNano() / 1000000 // 转毫秒
if s.timestamp == now {
// 当同一时间戳精度毫秒下多次生成id会增加序列号
s.sequence = (s.sequence + 1) & sequenceMask
if s.sequence == 0 {
// 如果当前序列超出12bit长度则需要等待下一毫秒
// 下一毫秒将使用sequence:0
for now <= s.timestamp {
now = time.Now().UnixNano() / 1000000
}
}
} else {
// 不同时间戳精度毫秒下直接使用序列号0
s.sequence = 0
}
t := now - epoch
if t > timestampMax {
s.Unlock()
return epoch
}
s.timestamp = now
r := (t)<<timestampShift | (s.datacenterid << datacenteridShift) | (s.workerid << workeridShift) | (s.sequence)
s.Unlock()
return r
}