Bläddra i källkod

改良版雪花id

lazy y chen 2 år sedan
förälder
incheckning
e5acecc7ef

+ 12 - 37
Masuit.Tools.Abstractions/Systems/SnowFlake.cs

@@ -12,28 +12,23 @@ namespace Masuit.Tools.Systems
         #region 私有字段
 
         private static long _machineId; //机器码
-        private static long _dataId; //数据ID
         private static long _sequence; //计数从零开始
         private static long _lastTimestamp = -1L; //最后时间戳
 
         private const long Twepoch = 687888001020L; //唯一时间随机量
 
-        private const long MachineIdBits = 5L; //机器码字节数
-        private const long DataBits = 5L; //数据字节数
-        private const long MaxMachineId = -1L ^ -1L << (int)MachineIdBits; //最大机器码
-        private const long MaxDataBitId = -1L ^ (-1L << (int)DataBits); //最大数据字节数
+        private const int MachineBits = 10; //机器码字节数
 
-        private const long SequenceBits = 12L; //计数器字节数,12个字节用来保存计数码        
-        private const long MachineIdShift = SequenceBits; //机器码数据左移位数,就是后面计数器占用的位数
-        private const long DatacenterIdShift = SequenceBits + MachineIdBits;
-        private const long TimestampLeftShift = DatacenterIdShift + DataBits; //时间戳左移动位数就是机器码+计数器总字节数+数据字节数
-        private const long SequenceMask = -1L ^ -1L << (int)SequenceBits; //一毫秒内可以产生计数,如果达到该值则等到下一毫秒在进行生成
+        private const int SequenceBits = 12; //计数器字节数,12个字节用来保存计数码
+        private const int MachineLeft = SequenceBits; //机器码数据左移位数,就是后面计数器占用的位数
+        private const long TimestampLeft = MachineBits + SequenceBits; //时间戳左移动位数就是机器码+计数器总字节数+数据字节数
+        private const long SequenceMask = -1L ^ -1L << SequenceBits; //一毫秒内可以产生计数,如果达到该值则等到下一毫秒在进行生成
 
         private static readonly object SyncRoot = new object(); //加锁对象
         private static NumberFormater _numberFormater = new NumberFormater(36);
         private static SnowFlake _snowFlake;
 
-        #endregion
+        #endregion 私有字段
 
         /// <summary>
         /// 获取一个新的id
@@ -54,7 +49,7 @@ namespace Masuit.Tools.Systems
         /// </summary>
         public SnowFlake()
         {
-            Snowflakes(0, -1);
+            Snowflakes(0);
         }
 
         /// <summary>
@@ -63,40 +58,20 @@ namespace Masuit.Tools.Systems
         /// <param name="machineId">机器码</param>
         public SnowFlake(long machineId)
         {
-            Snowflakes(machineId, -1);
+            Snowflakes(machineId);
         }
 
-        /// <summary>
-        /// 构造函数
-        /// </summary>
-        /// <param name="machineId">机器码</param>
-        /// <param name="datacenterId">数据中心id</param>
-        public SnowFlake(long machineId, long datacenterId)
-        {
-            Snowflakes(machineId, datacenterId);
-        }
-
-        private void Snowflakes(long machineId, long datacenterId)
+        private void Snowflakes(long machineId)
         {
             if (machineId >= 0)
             {
-                if (machineId > MaxMachineId)
+                if (machineId > 1024)
                 {
                     throw new Exception("机器码ID非法");
                 }
 
                 _machineId = machineId;
             }
-
-            if (datacenterId >= 0)
-            {
-                if (datacenterId > MaxDataBitId)
-                {
-                    throw new Exception("数据中心ID非法");
-                }
-
-                _dataId = datacenterId;
-            }
         }
 
         /// <summary>
@@ -134,7 +109,7 @@ namespace Masuit.Tools.Systems
                 }
 
                 _lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
-                long id = ((timestamp - Twepoch) << (int)TimestampLeftShift) | (_dataId << (int)DatacenterIdShift) | (_machineId << (int)MachineIdShift) | _sequence;
+                long id = ((timestamp - Twepoch) << (int)TimestampLeft) | (_machineId << MachineLeft) | _sequence;
                 return id;
             }
         }
@@ -170,4 +145,4 @@ namespace Masuit.Tools.Systems
             return id.Substring(index);
         }
     }
-}
+}

+ 118 - 0
Masuit.Tools.Abstractions/Systems/SnowFlakeNew.cs

@@ -0,0 +1,118 @@
+using System;
+using System.Linq;
+using System.Net.NetworkInformation;
+using Masuit.Tools.DateTimeExt;
+using Masuit.Tools.Strings;
+
+namespace Masuit.Tools.Systems;
+
+/// <summary>
+/// 改良版雪花id
+/// </summary>
+public class SnowFlakeNew
+{
+    private readonly long _workerId; //机器ID
+    private const long Twepoch = 1692079923000L; //唯一时间随机量
+    private static long _sequence;
+    private const int SequenceBits = 12; //计数器字节数,10个字节用来保存计数码
+    private const long SequenceMask = -1L ^ -1L << SequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
+    private static long _lastTimestamp = -1L;
+    private static readonly object LockObj = new object();
+    private readonly NumberFormater _numberFormater = new NumberFormater(36);
+    private static SnowFlakeNew _snowFlake;
+
+    /// <summary>
+    /// 获取一个新的id
+    /// </summary>
+    public static string NewId => GetInstance().GetUniqueId();
+
+    /// <summary>
+    /// 创建一个实例
+    /// </summary>
+    /// <returns></returns>
+    public static SnowFlakeNew GetInstance()
+    {
+        return _snowFlake ??= new SnowFlakeNew();
+    }
+
+    /// <summary>
+    /// 默认构造函数
+    /// </summary>
+    public SnowFlakeNew()
+    {
+        var bytes = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault().GetPhysicalAddress().GetAddressBytes();
+        _workerId = bytes[4] << 4 | bytes[5];
+    }
+
+    /// <summary>
+    /// 构造函数
+    /// </summary>
+    /// <param name="machineId">机器码</param>
+    public SnowFlakeNew(int machineId)
+    {
+        _workerId = machineId;
+    }
+
+    public long GetLongId()
+    {
+        lock (LockObj)
+        {
+            long timestamp = DateTime.Now.GetTotalMilliseconds();
+            if (_lastTimestamp == timestamp)
+            { //同一微妙中生成ID
+                _sequence = (_sequence + 1) & SequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限
+                if (_sequence == 0)
+                {
+                    //一微妙内产生的ID计数已达上限,等待下一微妙
+                    timestamp = DateTime.Now.GetTotalMilliseconds();
+                    while (timestamp <= _lastTimestamp)
+                    {
+                        timestamp = DateTime.Now.GetTotalMilliseconds();
+                    }
+                    return timestamp;
+                }
+            }
+            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 << 52 | (timestamp - Twepoch << 12) | _sequence;
+        }
+    }
+
+    /// <summary>
+    /// 获取一个字符串表示形式的id
+    /// </summary>
+    /// <returns></returns>
+    public string GetUniqueId()
+    {
+        return _numberFormater.ToString(GetLongId());
+    }
+
+    /// <summary>
+    /// 获取一个字符串表示形式的id
+    /// </summary>
+    /// <param name="maxLength">最大长度,至少6位</param>
+    /// <returns></returns>
+    public string GetUniqueShortId(int maxLength = 8)
+    {
+        if (maxLength < 6)
+        {
+            throw new ArgumentException("最大长度至少需要6位");
+        }
+
+        string id = GetUniqueId();
+        int index = id.Length - maxLength;
+        if (index < 0)
+        {
+            index = 0;
+        }
+
+        return id.Substring(index);
+    }
+}