golang 实现twitter雪花算法
Posted blogbobo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于golang 实现twitter雪花算法的主要内容,如果未能解决你的问题,请参考以下文章
Java实现雪花算法(snowflake)-生成永不重复的ID(源代码+工具类)使用案例