唯一性ID生成器:
using System; using System.Collections.Generic; using System.Text; namespace Test.Core { /// <summary> /// 唯一性ID生成器 /// </summary> public class SFID { /// <summary> /// 初始基准时间戳,小于当前时间点即可 /// 分布式项目请保持此时间戳一致 /// </summary> private static long _twepoch = 0L; /// <summary> /// 毫秒计数器 /// </summary> private static long sequence = 0L; /// <summary> /// 最大机器ID所占的位数 /// </summary> private static long maxWorkerId = 90; /// <summary> /// 一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成 /// </summary> private static long sequenceMask = 99; /// <summary> /// 最后一次的时间戳 /// </summary> private static long lastTimestamp = -1L; /// <summary> /// 线程锁对象 /// </summary> private static object locker = new object(); /// <summary> /// 机器码 /// </summary> private static long _workerId = 99; /// <summary> /// 机器编号 /// </summary> public static long WorkerID { get { return _workerId; } set { if (value >= 0 && value < maxWorkerId) _workerId = value; else throw new Exception($"机器码必须在0至{ maxWorkerId}之间"); } } /// <summary> /// 获取多个集合 /// </summary> /// <param name="totalCount"></param> /// <returns></returns> public static IEnumerable<long> NewID(int totalCount) { for (var i = 0; i < totalCount; i++) { yield return NewID(); } } /// <summary> /// 机器编码的基数 /// </summary> private static long _workerBasic = 10000000000000L; /// <summary> /// 获取新的ID /// </summary> /// <returns></returns> public static long NewID() { lock (locker) { //WorkerID = workId; long timestamp = timeGen(); if (lastTimestamp == timestamp) { //同一微妙中生成ID sequence++; //用&运算计算该微秒内产生的计数是否已经到达上限 if (sequence > sequenceMask) { //一微妙内产生的ID计数已达上限,等待下一微妙 timestamp = tillNextMillis(lastTimestamp); } } else { //不同微秒生成ID sequence = 0; //计数清0 } if (timestamp < lastTimestamp) { //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过 throw new Exception($"Clock moved backwards. Refusing to generate id for {lastTimestamp - timestamp} milliseconds"); } lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳 return WorkerID * _workerBasic + lastTimestamp * 100 + sequence; } } ///// <summary> ///// 获取新的ID ///// </summary> ///// <param name="workId"></param> ///// <returns></returns> //public static long NewID(int workId) //{ // WorkerID = workId; // return NewID(); //} /// <summary> /// 获取下一微秒时间戳 /// </summary> /// <param name="lastTimestamp"></param> /// <returns></returns> private static long tillNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } sequence = 0; return timestamp; } private static DateTime _date = new DateTime(2019, 1, 1, 0, 0, 0, DateTimeKind.Utc); /// <summary> /// 当前时间戳 /// </summary> /// <returns></returns> private static long timeGen() { return (long)(DateTime.UtcNow - _date).TotalMilliseconds; } } }
调用:
long ID = SFID.NewID();