马上加入IBC程序猿 各种源码随意下,各种教程随便看! 注册 每日签到 加入编程讨论群

C#教程 ASP.NET教程 C#视频教程程序源码享受不尽 C#技术求助 ASP.NET技术求助

【源码下载】 社群合作 申请版主 程序开发 【远程协助】 每天乐一乐 每日签到 【承接外包项目】 面试-葵花宝典下载

官方一群:

官方二群:

雪花算法

  [复制链接]
查看1706 | 回复8 | 2023-7-31 15:40:02 | 显示全部楼层 |阅读模式
[C#] 纯文本查看 复制代码
    /// <summary>
    /// 雪花算法
    /// </summary>
    public class Snowflake
    {
        private const long twepoch = 1675235380000L;//当前时间戳
        private const int workerIdBits = 5; //机器id所占的位数
        private const int datacenterIdBits = 5; //数据标识id所占的位数
        private long maxWorkerId = -1L ^ (-1L << workerIdBits); //支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
        private long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); //支持的最大数据标识id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
        private const int sequenceBits = 22 - workerIdBits - datacenterIdBits; //计数器字节数,12个字节用来保存计数码
        private const int workerIdShift = sequenceBits; //机器码数据左移位数,就是后面计数器占用的位数
        private const int datacenterIdShift = sequenceBits + workerIdBits; //数据标识id向左移17位(12+5)
        private int timestampLeftShift = datacenterIdShift + datacenterIdBits; //时间截向左移22位(5+5+12)
        private long sequenceMask = -1L ^ (-1L << sequenceBits); //生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) 


        private long workerId = 1; //工作机器ID(0~31)
        private long datacenterId = 1; //数据中心ID(0~31)
        private long sequence = 0L;//毫秒内序列(0~4095)
        private long lastTimestamp = -1L; //上次生成ID的时间截
        private readonly object lockObj = new object();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="workerId">机器ID(0-31)</param>
        /// <param name="datacenterId">数据中心ID(0-31)</param>
        public Snowflake(int workerId, int datacenterId)
        {
            if (workerId > maxWorkerId || workerId < 0)
                throw new Exception($"机器ID 不能超过{maxWorkerId}");
            if (datacenterId > maxDatacenterId || datacenterId < 0)
                throw new Exception($" 数据中心ID 不能超过{maxDatacenterId}");
            this.workerId = workerId;
            this.datacenterId = datacenterId;
        }

        public long Nextval
        {
            get
            {
                lock (lockObj)
                {
                    return nextId();
                }
            }
        }

        /// <summary>
        /// 获取下一位ID
        /// </summary>
        private long nextId()
        {
            long timestamp = timeGen();
            if (lastTimestamp == timestamp)
            {
                //同一微妙中生成ID
                sequence = (sequence + 1) & sequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限
                if (sequence == 0)
                {
                    //一微妙内产生的ID计数已达上限,等待下一微妙
                    timestamp = tillNextMillis(lastTimestamp);
                }
            }
            else
            {
                //不同微秒生成ID
                sequence = 0; //计数清0
            }
            if (timestamp < lastTimestamp)
            {
                //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过
                throw new Exception(string.Format("Clock moved backwards.  Refusing to generate id for {0} milliseconds",
                     lastTimestamp - timestamp));
            }
            lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
            long nextId = ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;
            return nextId;
        }

        /// <summary>
        /// 获取下一微秒时间戳
        /// </summary>
        /// <param name="lastTimestamp"></param>
        /// <returns></returns>
        private  long tillNextMillis(long lastTimestamp)
        {
            long timestamp = timeGen();
            while (timestamp <= lastTimestamp)
            {
                timestamp = timeGen();
            }
            return timestamp;
        }


        /// <summary>
        /// 生成当前时间戳
        /// </summary>
        /// <returns></returns>
        private  long timeGen()
        {
            return ToTimestamp(DateTime.Now);
        }

        /// <summary>
        /// 获取当前的时间戳, 返回13位/10位时间戳
        /// </summary>
        /// <param name="time"></param>
        /// <param name="isGet10Bits">是否获取10位时间戳, 默认flase</param>
        /// <returns></returns>
        public long ToTimestamp(DateTime time, bool isGet10Bits = false)
        {
            long val = 0L;
            try
            {
                TimeSpan ts = time - new DateTime(1970, 1, 1, 0, 0, 0, 0);
                val = Convert.ToInt64(ts.TotalMilliseconds);

                if (isGet10Bits)
                    val /= 1000;
            }
            catch (Exception ex)
            {
                throw;
            }
            return val;
        }
    }

ibcadmin | 2023-8-1 18:38:34 | 显示全部楼层
很久没见你了...










点评

楠哥,俺又要无业了  详情 回复 发表于 2023-8-3 16:19
C#论坛 www.ibcibc.com IBC编程社区
C#
C#论坛
IBC编程社区
剑弑 | 2023-8-3 16:19:47 | 显示全部楼层
ibcadmin 发表于 2023-8-1 18:38
很久没见你了...

楠哥,俺又要无业了
ibcadmin | 2023-8-14 10:16:11 | 显示全部楼层
剑弑 发表于 2023-8-3 16:19
楠哥,俺又要无业了

  大好前途等着你呢  




点评

承你贵言  详情 回复 发表于 2023-8-28 14:46
C#论坛 www.ibcibc.com IBC编程社区
C#
C#论坛
IBC编程社区
剑弑 | 2023-8-28 14:46:17 | 显示全部楼层
ibcadmin 发表于 2023-8-14 10:16
大好前途等着你呢

承你贵言
*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则