• C# 实现 Snowflake算法 ID生成


    可供参考的:https://www.cnblogs.com/shiningrise/p/5727895.html

    using System;
    using System.Configuration;
    
    namespace Common.IdGenerator
    {
        public class SnowflakeIdGenerator
        {
            //基准时间
            public const long Twepoch = 1288834974657L;
            //机器标识位数
            const int WorkerIdBits = 5;
            //数据标志位数
            const int DatacenterIdBits = 5;
            //序列号识位数
            const int SequenceBits = 12;
            //最大支持机器节点数0~31,一共32个
            const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits);
            //最大支持数据中心节点数0~31,一共32个
            const long MaxDatacenterId = -1L ^ (-1L << DatacenterIdBits);
            //序列号ID最大值
            private const long SequenceMask = -1L ^ (-1L << SequenceBits);
            //机器ID偏左移12位
            private const int WorkerIdShift = SequenceBits;
            //数据ID偏左移17位
            private const int DatacenterIdShift = SequenceBits + WorkerIdBits;
            //时间毫秒左移22位
            public const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits;
    
            private long _sequence = 0L;
            private long _lastTimestamp = -1L;
    
            public long WorkerId { get; protected set; }
            public long DatacenterId { get; protected set; }
            public long Sequence
            {
                get { return _sequence; }
                internal set { _sequence = value; }
            }
    
            public SnowflakeIdGenerator(long workerId, long datacenterId, long sequence = 0L)
            {
                // 如果超出范围就抛出异常
                if (workerId > MaxWorkerId || workerId < 0)
                {
                    throw new ArgumentException(string.Format("worker Id 必须大于0,且不能大于MaxWorkerId: {0}", MaxWorkerId));
                }
    
                if (datacenterId > MaxDatacenterId || datacenterId < 0)
                {
                    throw new ArgumentException(string.Format("region Id 必须大于0,且不能大于MaxWorkerId: {0}", MaxDatacenterId));
                }
    
                //先检验再赋值
                WorkerId = workerId;
                DatacenterId = datacenterId;
                _sequence = sequence;
            }
    
            readonly object _lock = new Object();
            public virtual long NextId()
            {
                lock (_lock)
                {
                    var timestamp = TimeGen();
                    if (timestamp < _lastTimestamp)
                    {
                        throw new Exception(string.Format("时间戳必须大于上一次生成ID的时间戳.  拒绝为{0}毫秒生成id", _lastTimestamp - timestamp));
                    }
    
                    //如果上次生成时间和当前时间相同,在同一毫秒内
                    if (_lastTimestamp == timestamp)
                    {
                        //sequence自增,和sequenceMask相与一下,去掉高位
                        _sequence = (_sequence + 1) & SequenceMask;
                        //判断是否溢出,也就是每毫秒内超过1024,当为1024时,与sequenceMask相与,sequence就等于0
                        if (_sequence == 0)
                        {
                            //等待到下一毫秒
                            timestamp = TilNextMillis(_lastTimestamp);
                        }
                    }
                    else
                    {
                        //如果和上次生成时间不同,重置sequence,就是下一毫秒开始,sequence计数重新从0开始累加,
                        //为了保证尾数随机性更大一些,最后一位可以设置一个随机数
                        _sequence = 0;//new Random().Next(10);
                    }
    
                    _lastTimestamp = timestamp;
                    return ((timestamp - Twepoch) << TimestampLeftShift) | (DatacenterId << DatacenterIdShift) | (WorkerId << WorkerIdShift) | _sequence;
                }
            }
    
            // 防止产生的时间比之前的时间还要小(由于NTP回拨等问题),保持增量的趋势.
            protected virtual long TilNextMillis(long lastTimestamp)
            {
                var timestamp = TimeGen();
                while (timestamp <= lastTimestamp)
                {
                    timestamp = TimeGen();
                }
                return timestamp;
            }
    
            // 获取当前的时间戳
            protected virtual long TimeGen()
            {
                return TimeExtensions.CurrentTimeMillis();
            }
        }
    
        public static class TimeExtensions
        {
            public static Func<long> currentTimeFunc = InternalCurrentTimeMillis;
    
            public static long CurrentTimeMillis()
            {
                return currentTimeFunc();
            }
    
            public static IDisposable StubCurrentTime(Func<long> func)
            {
                currentTimeFunc = func;
                return new DisposableAction(() => currentTimeFunc = InternalCurrentTimeMillis);
            }
    
            public static IDisposable StubCurrentTime(long millis)
            {
                currentTimeFunc = () => millis;
                return new DisposableAction(() => currentTimeFunc = InternalCurrentTimeMillis);
            }
    
            private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    
            private static long InternalCurrentTimeMillis()
            {
                return (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds;
            }
        }
    
        public class DisposableAction : IDisposable
        {
            readonly Action _action;
    
            public DisposableAction(Action action)
            {
                if (action == null)
                    throw new ArgumentNullException("action");
                _action = action;
            }
    
            public void Dispose()
            {
                _action();
            }
        }
    }
    using System.Configuration;
    using System.Xml;
    using Common;
    
    namespace Configuration
    {
        public class SnowflakeConfig : ConfigSectionHandlerBase<SnowflakeConfig>
        {
            public long WorkerId { get; set; }
            public long DataCenterId { get; set; }
            public long Sequence { get; set; }
    
            public static SnowflakeConfig Instance
            {
                get
                {
                    if (Singleton<SnowflakeConfig>.Instance == null)
                        Singleton<SnowflakeConfig>.Instance = ConfigurationManager.GetSection("Snowflake") as SnowflakeConfig;
                    return Singleton<SnowflakeConfig>.Instance;
                }
            }
    
            public override object Create(object parent, object configContext, XmlNode section)
            {
                var config = new SnowflakeConfig();
    
                config.WorkerId = section.GetNode("WorkerId").GetAttributeValue("value").ToLong();
                config.DataCenterId = section.GetNode("DataCenterId").GetAttributeValue("value").ToLong();
                config.Sequence = section.GetNode("Sequence").GetAttributeValue("value").ToLong();
    
                return config;
            }
        }
    }
    <Snowflake>
      <!--小于等于31-->
      <WorkerId value="1"/>
      <!--小于等于31-->
      <DataCenterId value="1"/>
      <!--小于等于4095-->
      <Sequence value="1"/>
    </Snowflake>
  • 相关阅读:
    Maven的pom文件依赖提示 ojdbc6 Missing artifact,需要手动下载并导入maven参考
    Maven全局配置文件settings.xml详解(转)
    SpringBoot -- 项目结构+启动流程
    64匹马,8个赛道,找出前4名最少比赛多少场?——最快10次,最慢11次;
    Spring家族主流成员介绍
    java 中文与unicode互转
    Netty的Marshalling编解码器
    解决svn迁移过程中出现:SVN Error: is not the same repository as的问题
    netty入门实例
    Dubbo的使用及原理
  • 原文地址:https://www.cnblogs.com/jianghaidong/p/10190034.html
Copyright © 2020-2023  润新知