编程知识 cdmana.com

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 

| 或算法 

 

版权声明
本文为[CaiFengJian]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/DDSkay/p/13963225.html

Scroll to Top