feat(Go-StudyExample):2020/12/16: 新增雪花算法实现
This commit is contained in:
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* @Author : huangzj
|
||||||
|
* @Time : 2020/12/16 9:32
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
|
||||||
|
package Snowflake
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
workerBits uint8 = 10
|
||||||
|
numberBits uint8 = 12
|
||||||
|
workerMax int64 = -1 ^ (-1 << workerBits)
|
||||||
|
numberMax int64 = -1 ^ (-1 << numberBits)
|
||||||
|
timeShift uint8 = workerBits + numberBits
|
||||||
|
workerShift uint8 = numberBits
|
||||||
|
startTime int64 = 1525705533000 // 如果在程序跑了一段时间修改了epoch这个值 可能会导致生成相同的ID
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
workerIDBits = uint64(5) // 10bit 工作机器ID中的 5bit workerID
|
||||||
|
dataCenterIDBits = uint64(5) // 10 bit 工作机器ID中的 5bit dataCenterID
|
||||||
|
sequenceBits = uint64(12)
|
||||||
|
|
||||||
|
maxWorkerID = int64(-1) ^ (int64(-1) << workerIDBits) //节点ID的最大值 用于防止溢出
|
||||||
|
maxDataCenterID = int64(-1) ^ (int64(-1) << dataCenterIDBits)
|
||||||
|
maxSequence = int64(-1) ^ (int64(-1) << sequenceBits)
|
||||||
|
|
||||||
|
timeLeft = uint8(22) // timeLeft = workerIDBits + sequenceBits // 时间戳向左偏移量
|
||||||
|
dataLeft = uint8(17) // dataLeft = dataCenterIDBits + sequenceBits
|
||||||
|
workLeft = uint8(12) // workLeft = sequenceBits // 节点IDx向左偏移量
|
||||||
|
// 2020-05-20 08:00:00 +0800 CST
|
||||||
|
twepoch = int64(1589923200000) // 常量时间戳(毫秒)
|
||||||
|
)
|
||||||
|
|
||||||
|
type Worker struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
LastStamp int64 // 记录上一次ID的时间戳
|
||||||
|
WorkerID int64 // 该节点的ID
|
||||||
|
DataCenterID int64 // 该节点的 数据中心ID
|
||||||
|
Sequence int64 // 当前毫秒已经生成的ID序列号(从0 开始累加) 1毫秒内最多生成4096个ID
|
||||||
|
}
|
||||||
|
|
||||||
|
//分布式情况下,我们应通过外部配置文件或其他方式为每台机器分配独立的id
|
||||||
|
func NewWorker(workerID, dataCenterID int64) *Worker {
|
||||||
|
return &Worker{
|
||||||
|
WorkerID: workerID,
|
||||||
|
LastStamp: 0,
|
||||||
|
Sequence: 0,
|
||||||
|
DataCenterID: dataCenterID,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Worker) getMilliSeconds() int64 {
|
||||||
|
return time.Now().UnixNano() / 1e6
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Worker) NextID() (uint64, error) {
|
||||||
|
w.mu.Lock()
|
||||||
|
defer w.mu.Unlock()
|
||||||
|
|
||||||
|
return w.nextID()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *Worker) nextID() (uint64, error) {
|
||||||
|
timeStamp := w.getMilliSeconds()
|
||||||
|
if timeStamp < w.LastStamp {
|
||||||
|
return 0, errors.New("time is moving backwards,waiting until")
|
||||||
|
}
|
||||||
|
|
||||||
|
if w.LastStamp == timeStamp {
|
||||||
|
|
||||||
|
w.Sequence = (w.Sequence + 1) & maxSequence
|
||||||
|
|
||||||
|
if w.Sequence == 0 {
|
||||||
|
for timeStamp <= w.LastStamp {
|
||||||
|
timeStamp = w.getMilliSeconds()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
w.Sequence = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
w.LastStamp = timeStamp
|
||||||
|
id := ((timeStamp - twepoch) << timeLeft) |
|
||||||
|
(w.DataCenterID << dataLeft) |
|
||||||
|
(w.WorkerID << workLeft) |
|
||||||
|
w.Sequence
|
||||||
|
|
||||||
|
return uint64(id), nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* @Author : huangzj
|
||||||
|
* @Time : 2020/12/16 9:32
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
|
||||||
|
package Snowflake
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
func TestSnowflake(t *testing.T) {
|
||||||
|
w := NewWorker(5, 5)
|
||||||
|
|
||||||
|
ch := make(chan uint64, 10000)
|
||||||
|
count := 10000
|
||||||
|
wg.Add(count)
|
||||||
|
defer close(ch)
|
||||||
|
//并发 count个goroutine 进行 snowFlake ID 生成
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
id, _ := w.NextID()
|
||||||
|
ch <- id
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
m := make(map[uint64]int)
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
id := <-ch
|
||||||
|
// 如果 map 中存在为 id 的 key, 说明生成的 snowflake ID 有重复
|
||||||
|
_, ok := m[id]
|
||||||
|
if ok {
|
||||||
|
fmt.Printf("repeat id %d\n", id)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
fmt.Printf("id: %d", id)
|
||||||
|
}
|
||||||
|
// 将 id 作为 key 存入 map
|
||||||
|
m[id] = i
|
||||||
|
}
|
||||||
|
// 成功生成 snowflake ID
|
||||||
|
fmt.Println("All", len(m), "snowflake ID Get successed!")
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
雪花算法
|
||||||
|
|
||||||
|
参考:[https://zhuanlan.zhihu.com/p/251066557](https://zhuanlan.zhihu.com/p/251066557)
|
||||||
|
|
||||||
|

|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
@@ -19,6 +19,8 @@ json与struct之间转换处理工具使用示例
|
|||||||
|
|
||||||
2020/12/15: 新增通过pinyin包获取中文拼音的使用示例
|
2020/12/15: 新增通过pinyin包获取中文拼音的使用示例
|
||||||
|
|
||||||
|
2020/12/16: 新增雪花算法实现
|
||||||
|
|
||||||
# mod vendor模式加载包
|
# mod vendor模式加载包
|
||||||
通过go mod的方式加载的github上面的包会有报红的问题,但是包本身是可以运行的,这样就是会有一个问题,如果你想要点击去看方法的内容,没办法做到
|
通过go mod的方式加载的github上面的包会有报红的问题,但是包本身是可以运行的,这样就是会有一个问题,如果你想要点击去看方法的内容,没办法做到
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user