1. 程式人生 > 實用技巧 >SnowFlake全域性唯一ID演算法C#實現事例

SnowFlake全域性唯一ID演算法C#實現事例

public class SnowFlake
    {
        /// <summary>
        /// 總機器位數
        /// </summary>
        private static readonly int WorkBits = 5;
        /// <summary>
        /// 自增序列號位數
        /// </summary>
        private static readonly int SequenceBits = 16;
        /// <summary>
        /// 序列號最大值 0開始 
        
/// </summary> private static readonly long SequenceMax = 1L << SequenceBits; /// <summary> /// 伺服器最大值 /// </summary> private static readonly long WorkMax = 1L << WorkBits; /// <summary> /// 當前機器號 0-WorkMax /// </summary>
private static long CurrentWorkId = 0; /// <summary> /// 加鎖物件 /// </summary> private readonly object objlock = new object(); /// <summary> /// 記錄上次時間戳 /// </summary> private static long LastTime; /// <summary> ///
當前序列號 0開始 /// </summary> private static long CurrentSequence = -1; public SnowFlake(int _CurrentWorkId) { CurrentWorkId = _CurrentWorkId; Console.WriteLine(SequenceMax); } /// <summary> /// 自定義時間戳 /// </summary> /// <returns></returns> private long GetTime() { return (long)(DateTime.UtcNow - new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds; } /// <summary> /// 獲取ID /// </summary> /// <returns></returns> public long NextId() { lock (objlock) { if (CurrentWorkId >= WorkMax) { throw new Exception($"機器碼不能大於最大機器碼值{WorkMax}"); } var time = GetTime(); //同秒內序列號自增 if (time == LastTime) { //序列號超出最大 等待下一個時間點 if (CurrentSequence >= SequenceMax) { //等待下一個時間點 while (time == LastTime) { time = GetTime(); } CurrentSequence = -1; LastTime = time; } } else { //不同秒 重新自增 CurrentSequence = -1; LastTime = time; } CurrentSequence++; //Console.WriteLine(DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss fff")); //Console.WriteLine(CurrentSequence); var num = (WorkBits + SequenceBits); return time << num | CurrentWorkId << SequenceBits | CurrentSequence; } } }

以上程式碼為個人理解寫法,若有不足,請指正。

實際的演算法為 1個0bit+41bit時間戳+10bit機器碼+12bit序列號; 最終得到的是64bit的二進位制 也就是能支援int64最大值,可支援單機器每秒400多W的ID生成;

但js的最大Number型別是53bit,且常用系統也達不到這麼多併發,所以參考了廖雪峰老師的意見 修改為

32bit的秒級時間戳(現計算結果為31bit)+5bit的機器碼+16bit的序列號 共53bit,而且時間戳未使用1970預設演算法,採用了自定義年份,以上程式碼可支援最大2^5=32個機器 每臺機器2^16=65535個ID生成。

SnowFlake演算法其他理解參考https://www.cnblogs.com/firstdream/p/9055771.html

檢視int的bit可用Convert.ToString(num, 2);檢視

<< 左偏移 右邊補齊0

| 或演算法