go实现雪花算法

一、雪花算法介绍

1. 由来

        雪花算法英文名为SnowFlake,故为雪花。最早是 Twitter 公司在其内部用于分布式环境下生成唯一 ID

2.作用:

        雪花算法可以在分布式环境下生成全局唯一的int64类型的id。

3. 原理:

  • 首先雪花算法由64位构成。
  • 第一位永远为0。
  • 后41位为unix毫秒。所以 2^41/(1000*3600*24*364) ~=  69.73,能保存69年左右,当然毫秒需要减去一个初始值,可以是业务运行开始时的毫秒数,这样算法才能用69年,超过69年就会发生id重复。
  • 后10位分别为机器id和服务id,它们的范围都为0~31
  • 最后10位为去重序列号,如果两次分配id在一个毫秒内,就用这个序列号来区分。也就是说雪花算法在一个实例上一毫秒可以产生4096个id。

二、实现

        1.常量定义

const (
	machineBits  = int64(5)  //机器id位数
	serviceBits  = int64(5)  //服务id位数
	sequenceBits = int64(12) //序列id位数

	maxMachineID  = int64(-1) ^ (int64(-1) << machineBits)  //最大机器id
	maxServiceID  = int64(-1) ^ (int64(-1) << serviceBits)  //最大服务id
	maxSequenceID = int64(-1) ^ (int64(-1) << sequenceBits) //最大序列id

	timeLeft    = uint8(22) //时间id向左移位的量
	machineLeft = uint8(17) //机器id向左移位的量
	serviceLeft = uint8(12) //服务id向左移位的量

	twepoch = int64(1667972427000) //初始毫秒,时间是: Wed Nov  9 13:40:27 CST 2022
)

        2.代码


type Worker struct {
	sync.Mutex
	lastStamp  int64
	machineID  int64 //机器id,0~31
	serviceID  int64 //服务id,0~31
	sequenceID int64
}

func NewWorker(machineID, serviceID int64) *Worker {
	return &Worker{
		lastStamp:  0,
		machineID:  machineID,
		serviceID:  serviceID,
		sequenceID: 0,
	}
}

func (w *Worker) GetID() int64 {
	//多线程互斥
	w.Lock()
	defer w.Unlock()

	mill := time.Now().UnixMilli()

	if mill == w.lastStamp {
		w.sequenceID = (w.sequenceID + 1) & maxSequenceID
		//当一个毫秒内分配的id数>4096个时,只能等待到下一毫秒去分配。
		if w.sequenceID == 0 {
			for mill > w.lastStamp {
				mill = time.Now().UnixMilli()
			}
		}
	} else {
		w.sequenceID = 0
	}

	w.lastStamp = mill
	//fmt.Println(w.lastStamp - twepoch)
	//fmt.Println((w.lastStamp - twepoch) << timeLeft)
	//fmt.Printf("%b\n", (w.lastStamp-twepoch)<<timeLeft)
	id := (w.lastStamp-twepoch)<<timeLeft | w.machineID<<machineLeft | w.serviceID<<serviceLeft | w.sequenceID
	return id
}

三、测试

10000个协程同时请求id:


var work = NewWorker(30, 30)

func main() {
	var wg sync.WaitGroup

	count := 10000
	ch := make(chan int64, count)

	wg.Add(count)
	defer close(ch)
	//并发 count个goroutine 进行 snowFlake ID 生成
	for i := 0; i < count; i++ {
		go func() {
			defer wg.Done()
			id := work.GetID()
			ch <- id
		}()
	}
	wg.Wait()
	m := make(map[int64]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
		}
		// 将 id 作为 key 存入 map
		m[id] = i
	}
	// 成功生成 snowflake ID
	fmt.Println("All", len(m), "snowflake ID Get successed!")
}

结果:

        

参考文献:

        最详细的雪花算法讲解,包教包会(go版本)_51CTO博客_雪花算法解析

        雪花算法(SnowFlake)_文丑颜不良啊的博客-CSDN博客_雪花算法

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值