UUID(Universally Unique Identifier)是一种128位的全局唯一标识符。它通常用于标识信息,不依赖中央协调机构,因此在分布式系统中特别有用。生成连续的UUID并不是UUID设计的目标,因为UUID的主要目的是确保唯一性,而不是顺序性。然而,可以通过某些方法生成具有一定顺序性的UUID。

以下是一个基于时间戳和自增计数器的顺序UUID生成器的实现:

package main

import (
	"encoding/binary"
	"fmt"
	"sync"
	"time"

	"github.com/google/uuid"
)

type SequentialUUIDGenerator struct {
	mu            sync.Mutex
	lastTimestamp int64
	counter       uint64
}

func NewSequentialUUIDGenerator() *SequentialUUIDGenerator {
	return &SequentialUUIDGenerator{}
}

func (gen *SequentialUUIDGenerator) Generate() uuid.UUID {
	gen.mu.Lock()
	defer gen.mu.Unlock()

	currentTimestamp := time.Now().UnixNano() / int64(time.Millisecond)
	if currentTimestamp != gen.lastTimestamp {
		gen.lastTimestamp = currentTimestamp
		gen.counter = 0
	} else {
		gen.counter++
	}

	// 将时间戳和计数器合并为UUID
	var uuidBytes [16]byte
	binary.BigEndian.PutUint64(uuidBytes[:8], uint64(currentTimestamp))
	binary.BigEndian.PutUint64(uuidBytes[8:], gen.counter)

	newUUID, err := uuid.FromBytes(uuidBytes[:])
	if err != nil {
		panic(err)
	}

	return newUUID
}

func main() {
	generator := NewSequentialUUIDGenerator()
	for i := 0; i < 10; i++ {
		fmt.Println(generator.Generate())
	}
}

解释

  1. 结构体与初始化
    • SequentialUUIDGenerator 结构体包含了一个互斥锁(sync.Mutex),一个记录上一次生成UUID时的时间戳(lastTimestamp),以及一个计数器(counter)。
    • NewSequentialUUIDGenerator 函数用于初始化生成器。
  2. 生成UUID方法
    • Generate 方法获取当前时间戳(以毫秒为单位),并与上次的时间戳进行比较。
    • 如果当前时间戳与上次不相同,则重置计数器;否则计数器递增。
    • 将时间戳和计数器合并为一个16字节的数组,并转换为UUID。
  3. 主函数
    • main函数中,创建一个生成器实例并生成10个UUID进行打印。

使用互斥锁

为了确保生成UUID时的线程安全,使用了互斥锁(sync.Mutex)来保护对lastTimestampcounter的访问。

注意事项

  • 生成的UUID不是标准的UUID格式,但在一定程度上能满足顺序性的需求。
  • 使用了github.com/google/uuid包来处理UUID相关操作。如果没有该包,可以通过go get github.com/google/uuid来安装。

通过这种方式,您可以在Go语言中生成具有顺序性的UUID。

上面的代码生成的UUID是一个标准的UUID格式,它是一个包含数字和字母的字符串。例如,生成的UUID可能看起来像这样:

6b8b4567-88b5-42c5-91e6-6f573d93c9f4

如果您希望生成一个纯数字的顺序UUID,可以调整代码以生成只包含数字的字符串。以下是一个示例:

package main

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

type SequentialUUIDGenerator struct {
	mu            sync.Mutex
	lastTimestamp int64
	counter       uint64
}

func NewSequentialUUIDGenerator() *SequentialUUIDGenerator {
	return &SequentialUUIDGenerator{}
}

func (gen *SequentialUUIDGenerator) Generate() string {
	gen.mu.Lock()
	defer gen.mu.Unlock()

	currentTimestamp := time.Now().UnixNano() / int64(time.Millisecond)
	if currentTimestamp != gen.lastTimestamp {
		gen.lastTimestamp = currentTimestamp
		gen.counter = 0
	} else {
		gen.counter++
	}

	// 将时间戳和计数器合并为一个字符串
	// 时间戳的长度为13位,计数器的长度可以根据需要调整
	return fmt.Sprintf("%013d%05d", currentTimestamp, gen.counter)
}

func main() {
	generator := NewSequentialUUIDGenerator()
	for i := 0; i < 10; i++ {
		fmt.Println(generator.Generate())
	}
}

生成的结果

生成的结果将是一个包含纯数字的字符串,例如:

162378907100000
162378907100001
162378907100002

如果需要生成较短的纯数字顺序UUID,可以通过缩短时间戳的位数以及控制计数器的位数。以下是一个示例,使用当前时间戳(秒级)并结合一个较短的计数器来生成较短的纯数字顺序UUID:

package main

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

type SequentialUUIDGenerator struct {
	mu            sync.Mutex
	lastTimestamp int64
	counter       int
}

func NewSequentialUUIDGenerator() *SequentialUUIDGenerator {
	return &SequentialUUIDGenerator{}
}

func (gen *SequentialUUIDGenerator) Generate() string {
	gen.mu.Lock()
	defer gen.mu.Unlock()

	// 获取当前时间戳的秒部分,并只取后5位
	currentTimestamp := time.Now().Unix() % 100000

	if currentTimestamp != gen.lastTimestamp {
		gen.lastTimestamp = currentTimestamp
		gen.counter = 0
	} else {
		gen.counter++
	}

	// 将时间戳和计数器合并为一个字符串,控制其总长度在10位以内
	return fmt.Sprintf("%05d%04d", currentTimestamp, gen.counter)
}

func main() {
	generator := NewSequentialUUIDGenerator()
	for i := 0; i < 10; i++ {
		fmt.Println(generator.Generate())
	}
}

解释

  1. 结构体与初始化
    • SequentialUUIDGenerator 结构体包含一个互斥锁(sync.Mutex),一个记录上一次生成UUID时的时间戳(lastTimestamp),以及一个计数器(counter)。
    • NewSequentialUUIDGenerator 函数用于初始化生成器。
  2. 生成UUID方法
    • Generate 方法获取当前时间戳的秒部分,并只取后5位。
    • 如果当前时间戳的秒部分与上次不同,则重置计数器;否则计数器递增。
    • 将时间戳和计数器合并为一个字符串,控制其总长度在10位以内。
  3. 主函数
    • main函数中,创建一个生成器实例并生成10个UUID进行打印。

生成的结果

生成的结果将是一个较短的纯数字字符串,例如:

123450000
123450001
123450002
...