This is an explanation of the video content.
 用技术延续对ACG的热爱
27

 |   | 

Go雪花算法生成数字id

使用Go语言实现雪花算法生成唯一ID

package main

import (
	"fmt"
	"sync"
	"time"
)

const (
	// 时间戳占用41位
	timestampBits = 41
	// 机器ID占用5位
	workerIdBits = 5
	// 序列号占用12位
	sequenceBits = 12

	// 最大机器ID
	maxWorkerId = -1 ^ (-1 << workerIdBits)
	// 最大序列号
	maxSequence = -1 ^ (-1 << sequenceBits)

	// 时间戳左移位数
	timestampLeftShift = sequenceBits + workerIdBits
	// 机器ID左移位数
	workerIdLeftShift = sequenceBits
)

type Snowflake struct {
	sync.Mutex
	workerId     int64
	sequence     int64
	lastTimestamp int64
}

func NewSnowflake(workerId int64) (*Snowflake, error) {
	if workerId < 0 || workerId > maxWorkerId {
		return nil, fmt.Errorf("worker Id must be between 0 and %d", maxWorkerId)
	}
	return &Snowflake{
		workerId:     workerId,
		lastTimestamp: -1,
	}, nil
}

func (s *Snowflake) NextId() int64 {
	s.Lock()
	defer s.Unlock()

	now := time.Now().UnixNano() / 1000000
	if now == s.lastTimestamp {
		s.sequence = (s.sequence + 1) & maxSequence
		if s.sequence == 0 {
			for now <= s.lastTimestamp {
				now = time.Now().UnixNano() / 1000000
			}
		}
	} else {
		s.sequence = 0
	}
	s.lastTimestamp = now
	id := ((now - 1420070400000) << timestampLeftShift) |
		(s.workerId << workerIdLeftShift) |
		s.sequence
	return id
}

func main() {
	snowflake, _ := NewSnowflake(1)
	fmt.Println(snowflake.NextId())
}

该代码实现了雪花算法的核心逻辑,包括:

  • 时间戳占用41位,机器ID占用5位,序列号占用12位。
  • 使用带锁的单例模式保证线程安全。
  • 在同一毫秒内生成不同的ID,如果超过同一毫秒的最大序列号,则等待下一毫秒。
  • 将时间戳、机器ID和序列号组合成64位的ID。
  • 可以根据需要调整参数,如workerIdBits和sequenceBits的值,来实现不同的ID生成策略。

27 服务端 ↦ Go开发技巧 __ 196 字
 Go开发技巧 #39