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 }