golang 实现twitter雪花算法

  1 /*
  2  * twitter雪花算法golang实现,生成唯一趋势自增id
  3  * 保留位:63位
  4  * 毫秒时间戳:[62-20]43位,时间范围[1970-01-01 00:00:00.000,2248-09-26 15:10:22.207]
  5  * 机器id:[19-12]8位,十进制范围[0,255]
  6  * 序列号:[11-0]12位,十进制范围[0,4095]
  7  * bobo
  8  */
  9 
 10 package test
 11 
 12 import (
 13     "runtime"
 14     "sync"
 15     "time"
 16 )
 17 
 18 type SnowFlake struct {
 19     machineID int64      //机器 id占8位,十进制范围是[0,255]
 20     sn        int64      //序列号占12位,十进制范围是[0,4095]
 21     lastTime  int64      //上次的时间戳(毫秒级)
 22     _lock     sync.Mutex //
 23 }
 24 
 25 var Snow = &SnowFlake{
 26     lastTime: time.Now().UnixNano() / 1000000,
 27 }
 28 
 29 func (c *SnowFlake) lock() {
 30     c._lock.Lock()
 31 }
 32 
 33 func (c *SnowFlake) unLock() {
 34     c._lock.Unlock()
 35 }
 36 
 37 //获取当前毫秒
 38 func (c *SnowFlake) getCurMilliSecond() int64 {
 39     return time.Now().UnixNano() / 1000000
 40 }
 41 
 42 //设置机器id,默认为0,范围[0,255]
 43 func (c *SnowFlake) SetMachineId(mId int64) {
 44     //保留8位
 45     mId = mId & 0xFF
 46     //左移12位,序列号是12位的
 47     mId <<= 12
 48     c.machineID = mId
 49 }
 50 
 51 //获取机器id
 52 func (c *SnowFlake) GetMachineId() int64 {
 53     mId := c.machineID
 54     mId >>= 12
 55     return mId | 0xFF
 56 }
 57 
 58 //解析雪花(id)
 59 // 返回值
 60 // milliSecond:毫秒数
 61 // mId:机器id
 62 // sn:序列号
 63 func (c *SnowFlake) ParseId(id int64) (milliSecond, mId, sn int64) {
 64     sn = id & 0xFFF
 65     id >>= 12
 66     mId = id & 0xFF
 67     id >>= 8
 68     milliSecond = id & 0x7FFFFFFFFFF
 69 
 70     return
 71 }
 72 
 73 //毫秒转换成time
 74 func (c *SnowFlake) MilliSecondToTime(milliSecond int64) (t time.Time) {
 75     return time.Unix(milliSecond/1000, milliSecond%1000*1000000)
 76 }
 77 
 78 //毫秒转换成"20060102T150405.999Z"
 79 func (c *SnowFlake) MillisecondToTimeTz(ts int64) string {
 80     tm := Snow.MilliSecondToTime(ts)
 81     return tm.UTC().Format("20060102T150405.999Z")
 82 }
 83 
 84 //毫秒转换成"2006-01-02 15:04:05.999"
 85 func (c *SnowFlake) MillisecondToTimeDb(ts int64) string {
 86     tm := Snow.MilliSecondToTime(ts)
 87     return tm.UTC().Format("2006-01-02 15:04:05.999")
 88 }
 89 
 90 //获取雪花
 91 //返回值
 92 //id:自增id
 93 //ts:生成该id的毫秒时间戳
 94 func (c *SnowFlake) GetSnowflakeId() (id, ts int64) {
 95     curTime := c.getCurMilliSecond()
 96     var sn int64 = 0
 97 
 98     c.lock()
 99     // 同一毫秒
100     if curTime == c.lastTime {
101         c.sn++
102         // 序列号占 12 位,十进制范围是 [0,4095]
103         if c.sn > 4095 {
104             for {
105                 // 让出当前线程
106                 runtime.Gosched()
107                 curTime = c.getCurMilliSecond()
108                 if curTime != c.lastTime {
109                     break
110                 }
111             }
112             c.sn = 0
113         }
114     } else {
115         c.sn = 0
116     }
117     sn = c.sn
118     c.lastTime = curTime
119     c.unLock()
120 
121     //当前时间小于上次的时间,系统时间改过了吗?
122     /*
123         if curTimeStamp < c.lastTimeStamp {
124                 return 0, curTimeStamp
125         }
126     */
127     //机器id占用8位空间,序列号占用12位空间,所以左移20位
128     rightBinValue := curTime & 0x7FFFFFFFFFF
129     rightBinValue <<= 20
130     id = rightBinValue | c.machineID | sn
131 
132     return id, curTime
133 }

测试

 1 func testFun() {
 2     var count int = 1000000
 3     mapId := make(map[int64]int64, count)
 4     fmt.Println("start,count:", count)
 5     for i := 0; i < count; i++ {
 6         id, ts := test.Snow.GetSnowflakeId()
 7         mapId[id] = ts
 8     }
 9     fmt.Println("done,count:", count, ",mapCount:", len(mapId))
10 }

 

posted on 2020-06-20 17:37  lijianbo  阅读(834)  评论(0编辑  收藏  举报

导航