一个简单的用C#实现的分布式雪花ID算法

server/2025/3/30 3:45:06/

雪花ID是一个依赖时间戳根据算法生成的一个Int64的数字ID,一般用来做主键或者订单号等。以下是一个用C#写的雪花ID的简单实现方法

using System;
using System.Collections.Concurrent;
using System.Diagnostics;public class SnowflakeIdGenerator
{// 配置常量private const int SignBits = 1;// 符号位private const int TimestampBits = 41;// 时间戳位,最大值2^41-1=2,147,483,647ms,69年private const int DataCenterIdBits = 4;// 数据中心ID位,最大值2^4-1=15private const int MachineIdBits = 6;// 机器ID位,最大值2^6-1=63private const int DefaultSequenceBits = 12;// 自增序号位,最大值2^12-1=4095private const int ProcessIdBits = 4;// 进程ID位,最大值2^4-1=15private const int SequenceBitsWithProcess = 8;//如果使用进程ID,则为8位,否则为12位,最大值2^8-1=255// 位移计算常量private const int TimestampShift = 64 - SignBits - TimestampBits;private const int DataCenterShift = TimestampShift - DataCenterIdBits;private const int MachineShift = DataCenterShift - MachineIdBits;private const int ProcessShift = SequenceBitsWithProcess;// 基准时间private static readonly DateTime Epoch = new(2025, 3, 1, 0, 0, 0, DateTimeKind.Utc);private const long MaxTimestamp = (1L << TimestampBits) - 1;// 单例存储private static readonly ConcurrentDictionary<string, SnowflakeIdGenerator> _instances = new();// 各ID最大值private readonly long _maxDataCenterId = (1 << DataCenterIdBits) - 1;private readonly long _maxMachineId = (1 << MachineIdBits) - 1;private readonly long _maxProcessId = (1 << ProcessIdBits) - 1;private readonly long _maxSequence;// 状态控制private readonly object _lock = new object();private long _lastTimestamp = -1L;private int _sequence = 0;// 节点信息public int DataCenterId { get; }// 数据中心IDpublic int MachineId { get; }// 机器IDpublic int ProcessId { get; }// 进程IDpublic bool UseProcessId { get; }// 是否使用进程IDprivate SnowflakeIdGenerator(int dataCenterId, int machineId, int processId){// 参数校验逻辑ValidateId(dataCenterId, (1 << DataCenterIdBits) - 1, nameof(dataCenterId));ValidateId(machineId, (1 << MachineIdBits) - 1, nameof(machineId));UseProcessId = processId != 0;if (UseProcessId){ValidateId(processId, (1 << ProcessIdBits) - 1, nameof(processId));}DataCenterId = dataCenterId;MachineId = machineId;ProcessId = processId;}public static SnowflakeIdGenerator GetInstance(int dataCenterId, int machineId, int processId = 0){var key = $"{dataCenterId}-{machineId}-{processId}";return _instances.GetOrAdd(key, _ => new SnowflakeIdGenerator(dataCenterId, machineId, processId));}/// <summary>/// 产生下一个ID/// </summary>/// <returns></returns>public long NextId(){lock (_lock){var timestamp = GetValidTimestamp();if (timestamp == _lastTimestamp){_sequence++;if (_sequence > MaxSequence){timestamp = WaitNextMillis(timestamp);_sequence = 0;}}else{_sequence = 0;}_lastTimestamp = timestamp;return BuildId(timestamp);}}/// <summary>/// 获取最大序号/// </summary>private int MaxSequence => UseProcessId ?(1 << SequenceBitsWithProcess) - 1 :(1 << DefaultSequenceBits) - 1;/// <summary>/// 拼接生成ID/// </summary>/// <param name="timestamp"></param>/// <returns></returns>private long BuildId(long timestamp){var id = (timestamp << TimestampShift)| ((long)DataCenterId << DataCenterShift)| ((long)MachineId << MachineShift);if (UseProcessId){return id | ((long)ProcessId << ProcessShift) | (uint)_sequence;}return id | (uint)_sequence;}/// <summary>/// 获取有效的时间戳,防止时间回拨或系统时钟溢出/// </summary>/// <returns></returns>/// <exception cref="InvalidOperationException"></exception>private long GetValidTimestamp(){var timestamp = (DateTimeOffset.UtcNow.Ticks - Epoch.Ticks) / TimeSpan.TicksPerMillisecond;if (timestamp < _lastTimestamp){throw new InvalidOperationException($"Clock moved backwards. Refusing to generate ID for {_lastTimestamp - timestamp}ms");}if (timestamp > MaxTimestamp){throw new InvalidOperationException($"System clock overflow. Timestamp exceeds {TimestampBits} bits.");}return timestamp;}// 等待下一毫秒,产生新的时间戳private static long WaitNextMillis(long currentTimestamp){long timestamp;var spinWait = new SpinWait();do{spinWait.SpinOnce();timestamp = (DateTimeOffset.UtcNow.Ticks - Epoch.Ticks) / TimeSpan.TicksPerMillisecond;} while (timestamp <= currentTimestamp);return timestamp;}// 校验ID,必须在0到最大值之间private static void ValidateId(int value, long maxValue, string paramName){if (value < 0 || value > maxValue){throw new ArgumentOutOfRangeException(paramName,$"Value must be between 0 and {maxValue}");}}
}

调用方式

 //获取单例实例var generator = SnowflakeIdGenerator.GetInstance(dataCenterId: 1, machineId: 5);//推荐long id = generator.NextId();//或者,加入进程IDvar generator = SnowflakeIdGenerator.GetInstance(dataCenterId: 1, machineId: 5, processId: 10);long id = generator.NextId();

http://www.ppmy.cn/server/179174.html

相关文章

数据库 第一章 MySql基础(1)

目录 数据库概述 定义 常见的数据库产品&#xff1a; Mysql数据库 MySQL的常用命令 安装可视化客户端工具 sql DDL 创建,删除数据库 数据库表的基本概念 设 计 表 设计表(数据类型) 字符 日期 整数 浮点 长文本字符 主键&#xff1a; 约束: 创建表语法: 删…

Solr-搜索引擎-入门到精通

以下是对 Apache Solr 的简介及其常用语法的快速入门指南&#xff1a; 一、Solr 是什么&#xff1f; • 核心定位&#xff1a;Apache Solr 是一个基于 Lucene 的高性能、开源的搜索平台&#xff0c;支持全文检索、分词、高亮、聚合统计等功能。 • 核心功能&#xff1a; • 全…

【视频】m3u8相关操作

1、视频文件转m3u8 1.1 常用命令 1)默认只保留 5 个ts文件 ffmpeg -i input.mp4 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls stream1.m3u82)去掉音频 -an,保留全部ts文件 ffmpeg -i input.mp4 -vf scale=640:480 -an -start_number 0 -hls_time 10 -hls_lis…

23种设计模式-观察者(Observer)设计模式

观察者设计模式 &#x1f6a9;什么是观察者模式&#xff1f;&#x1f6a9;观察者设计模式的特点&#x1f6a9;观察者设计模式的结构&#x1f6a9;观察者设计模式的优缺点&#x1f6a9;观察者设计模式的Java实现&#x1f6a9;代码总结&#x1f6a9;总结 &#x1f6a9;什么是观察…

人工智能与无人机:无人机的进步与应用技术详解

人工智能&#xff08;Artificial Intelligence&#xff0c;简称AI&#xff09;是一门研究、开发用于模拟、延伸和扩展人类智能的理论、方法、技术及应用系统的新技术科学。 无人机&#xff0c;全称为无人驾驶飞行器&#xff08;UAV&#xff09;&#xff0c;也称为无人机器人、…

Java 基础入门代码示例解析

在 Java 编程的学习过程中&#xff0c;理解函数&#xff08;方法&#xff09;的使用以及简单系统功能的实现是非常重要的基础。本文将对一系列 Java 代码进行详细解析&#xff0c;这些代码涵盖了菜单驱动的功能选择、数据查询以及简单的 RBAC&#xff08;基于角色的访问控制&am…

简单选择排序

简单选择排序&#xff0c;很明显属于选择排序。 选择排序&#xff1a;每一趟在待排序元素中选取关键字最小&#xff08;或最大&#xff09;的元素加入有序子序列。 n个元素的简单选择排序需要n-1趟处理。 代码&#xff1a; void SelectSort(int A[],int n){int min_idx;//记…

进程通信(进程池的模拟实现) read write函数复习 Linux ─── 第23课

目录 write和read函数补充: 进程池(process pool) 第一步: 创建并初始化processpool 第二步:主进程对子进程派发任务 补充: 第三步: 子进程执行完退出进程池 回收子进程 Channel.hpp ProcessPool.hpp Task.hpp main.cc makefile write和read函数补充: const char …