|
|
@@ -0,0 +1,176 @@
|
|
|
+using System.Reflection.PortableExecutable;
|
|
|
+
|
|
|
+namespace ApiDemo
|
|
|
+{
|
|
|
+ /// <summary>
|
|
|
+ /// 雪花算法生成id
|
|
|
+ /// </summary>
|
|
|
+ public class SnowFlake
|
|
|
+ {
|
|
|
+ /// <summary>
|
|
|
+ /// 机器id所占的位数
|
|
|
+ /// </summary>
|
|
|
+ private const int workerIdBits = 5;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 数据表述id所占位数
|
|
|
+ /// </summary>
|
|
|
+ private const int datacenterIdBits = 5;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 支持的最大机器id,结果是31
|
|
|
+ /// </summary>
|
|
|
+ private const long maxWorkerId = -1L ^ (-1L << workerIdBits);
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 支持的最大数据表示id,结果是31
|
|
|
+ /// </summary>
|
|
|
+ private const long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 序列在id中所占的位数
|
|
|
+ /// </summary>
|
|
|
+ private const int sequenceBits = 12;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 数据标识id向左移17位
|
|
|
+ /// </summary>
|
|
|
+ private const int datacenterIdShift = sequenceBits + workerIdBits;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 机器ID向左移12位
|
|
|
+ /// </summary>
|
|
|
+ private const int workerIdShift = sequenceBits;
|
|
|
+
|
|
|
+ private const int timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 生成序列的掩码
|
|
|
+ /// </summary>
|
|
|
+ private const long sequenceMask = -1L ^ (-1L << sequenceBits);
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 数据中心ID(0-31)
|
|
|
+ /// </summary>
|
|
|
+ public long DatacenterId { get; private set; }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 工作机器ID(0-31)
|
|
|
+ /// </summary>
|
|
|
+ public long WorkerId { get; private set; }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 毫秒内序列(0-4095)
|
|
|
+ /// </summary>
|
|
|
+ public long Sequence { get; private set; }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 上次生成ID的时间戳
|
|
|
+ /// </summary>
|
|
|
+ public long LastTimestamp { get; private set; }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 开始时间戳。首次使用前设置,否则无效,默认2010-1-1
|
|
|
+ /// </summary>
|
|
|
+ public DateTime StartTimestamp { get; set; } = new DateTime(2010,1,1);
|
|
|
+
|
|
|
+ static object syncRoot = new object();
|
|
|
+ static readonly Lazy<SnowFlake> snowflake = new(() => new SnowFlake(0L,0L));
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 默认金泰实例,WorkerId = 0,DatacenterId = 0
|
|
|
+ /// </summary>
|
|
|
+ public static SnowFlake Instance { get; } = snowflake.Value;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 构造函数
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="workerId">工作机器ID</param>
|
|
|
+ /// <param name="datacenterId">数据中心ID</param>
|
|
|
+ /// <exception cref="ArgumentOutOfRangeException"></exception>
|
|
|
+ public SnowFlake(long workerId,long datacenterId)
|
|
|
+ {
|
|
|
+ if (workerId > maxWorkerId || workerId < 0)
|
|
|
+ {
|
|
|
+ throw new ArgumentOutOfRangeException(nameof(workerId),$"不能大于{maxWorkerId}或小于0");
|
|
|
+ }
|
|
|
+ if (datacenterId > maxDatacenterId || datacenterId < 0)
|
|
|
+ {
|
|
|
+ throw new ArgumentOutOfRangeException(nameof(datacenterId), $"不能大于{maxDatacenterId}或小于0");
|
|
|
+ }
|
|
|
+ WorkerId = workerId;
|
|
|
+ DatacenterId = datacenterId;
|
|
|
+ Sequence = 0L;
|
|
|
+ LastTimestamp = -1L;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取下一个ID
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ public long NextId()
|
|
|
+ {
|
|
|
+ lock (syncRoot)
|
|
|
+ {
|
|
|
+ //获取当前时间戳
|
|
|
+ long timestamp = GetCurrentTimestamp();
|
|
|
+ if (timestamp > LastTimestamp)//时间戳改变,毫秒内序列重置
|
|
|
+ {
|
|
|
+ Sequence = 0L;
|
|
|
+ }
|
|
|
+ else if (timestamp == LastTimestamp)//如果是同一时间生成的,则进行毫秒内序列
|
|
|
+ {
|
|
|
+ Sequence = (Sequence + 1) & sequenceMask;
|
|
|
+ if (Sequence == 0)//毫秒内序列溢出
|
|
|
+ {
|
|
|
+ timestamp = GetNextTimestamp(LastTimestamp);//阻塞到下一个毫秒,获取新的时间戳
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else//当前时间小于上一次ID生成的时间戳,证明系统时钟被回拨,此时需要做回拨处理
|
|
|
+ {
|
|
|
+ Sequence = (Sequence + 1) & sequenceMask;
|
|
|
+ if (Sequence > 0)
|
|
|
+ {
|
|
|
+ timestamp = LastTimestamp;//停留再最后一次时间戳上,等待系统时间追上后即完全度过了时钟回拨问题
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ timestamp = LastTimestamp + 1;//直接进位到下一个毫秒
|
|
|
+ }
|
|
|
+ }
|
|
|
+ LastTimestamp = timestamp;//上次生成ID的时间戳
|
|
|
+
|
|
|
+ //移动并通过或运算拼到一起组成64位的ID
|
|
|
+ var id = (timestamp << timestampLeftShift)
|
|
|
+ | (DatacenterId << datacenterIdShift)
|
|
|
+ | (WorkerId << workerIdShift)
|
|
|
+ | Sequence;
|
|
|
+ return id;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 阻塞到下一个毫秒,直到获得新的时间戳
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="lastTimestamp"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private long GetNextTimestamp(long lastTimestamp)
|
|
|
+ {
|
|
|
+ //获取当前时间戳
|
|
|
+ long timestamp = GetCurrentTimestamp();
|
|
|
+ while (timestamp <= lastTimestamp)
|
|
|
+ {
|
|
|
+ timestamp = GetCurrentTimestamp();
|
|
|
+ }
|
|
|
+ return timestamp;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 获取当前时间戳
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private long GetCurrentTimestamp()
|
|
|
+ {
|
|
|
+ return (long)(DateTime.Now - StartTimestamp).TotalMilliseconds;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|