• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

c#分布式ID生成器

c# 搞代码 4年前 (2022-01-09) 15次浏览 已收录 0个评论

简介

这个是根据twitter的snowflake来写的.这里有中文的介绍.

如上图所示,一个64位ID,除了最左边的符号位不用(固定为0,以保证生成的ID都是正数),还剩余63位可用.

下面的代码与图中的位数分配略有不同,除了中间部分10bit工作机器id不变,时间戳和序列号的位数是可以根据自己的需求变化的,就是说,你可以把中间的工作机器ID往左挪一挪,或往右挪一挪.

代码

/// <summary>    /// 64位ID生成器,最高位为符号位,始终为0,可用位数63.    /// 实例编号占10位,范围为0-1023    /// 时间戳和索引共占53位    /// </summary>    public sealed class IdCreator    {        long timestamp = 0;//当前时间戳        long index = 0;//索引/计数器        long instanceID;//实例编号        int indexBitLength;//索引可用位数        long tsMax = 0;//时间戳最大值        long indexMax = 0;        static IdCreator _default = new IdCreator();        /// <summary>        ///         /// </summary>        /// 实例编号(0-1023)        /// 索引可用位数(1-32).每秒可生成ID数等于2的indexBitLength次方.大并发情况下,当前秒内ID数达到最大值时,将使用下一秒的时间戳,不影响获取ID.        /// 初始化时间戳,精确到秒.当之前同一实例生成ID的timestamp值大于当前时间的时间戳时,        /// 有可能会产生重复ID(如持续一段时间的大并发请求).设置initTimestamp比最后的时间戳大一些,可避免这种问题        public IdCreator(int instanceID, int indexBitLength, long? initTimestamp = null)        {            if (instanceID < 0)            {                //这里给每个实例随机生成个实例编号                Random r = new Random();                this.instanceID = r.Next(0, 1024);            }            else            {                this.instanceID = instanceID % 1024;            }            if (indexBitLength  32)            {                this.indexBitLength = 32;            }            else            {                this.indexBitLength = indexBitLength;            }            tsMax = Convert.ToInt64(new string('1', 53 - indexBitLength), 2);            indexMax = Convert.ToInt64(new string('1', indexBitLength), 2);            if (initTimestamp != null)            {                this.timestamp = initTimestamp.Value;            }        }        /// <summary>        /// 默认每实例每秒生成65536个ID,从1970年1月1日起,累计可使<b style="color:transparent">本文来源gao@!dai!ma.com搞$$代^@码!网!</b>用4358年        /// </summary>        /// 实例编号(0-1023)        public IdCreator(int instanceID) : this(instanceID, 16)        {        }        /// <summary>        /// 默认每秒生成65536个ID,从1970年1月1日起,累计可使用4358年        /// </summary>        public IdCreator() : this(-1)        {        }        /// <summary>        /// 生成64位ID        /// </summary>        ///         public long Create()        {            long id = 0;            lock (this)            {                //增加时间戳部分                long ts = Harry.Common.Utils.GetTimeStamp() / 1000;                ts = ts % tsMax;  //如果超过时间戳允许的最大值,从0开始                id = ts << (10 + indexBitLength);//腾出后面部分,给实例编号和缩引编号使用                //增加实例部分                id = id | (instanceID << indexBitLength);                //获取计数                if (timestamp  indexMax)                    {                        timestamp++;                        index = 0;                    }                }                id = id | index;                index++;            }            return id;        }        /// <summary>        /// 获取当前实例的时间戳        /// </summary>        public long CurrentTimestamp        {            get            {                return this.timestamp;            }        }        /// <summary>        /// 默认每实例每秒生成65536个ID,从1970年1月1日起,累计可使用4358年        /// </summary>        public static IdCreator Default        {            get            {                return _default;            }        }    }

代码说明

使用时,需要new一个IdCreator的实例,然后调用Create()方法,生成一个ID号.需要把IdCreator的例实赋给一个静态变量,以保证ID号的唯一性.如果是分布式部署,需要给IdCreator的构造函数传递instanceID参数,每一个部署都要有一个不同的值,范围为0-1023.

构造函数中的indexBitLength参数,代表图中最右边的'序列号'的长度,不再固定为12bit,范围为1-32.剩下的可用位,就留给了时间戳.

注意:IdCreator类的时间戳是按秒计的. 如果想改成毫秒,只需要将代码long ts = Harry.Common.Utils.GetTimeStamp() / 1000;改成long ts = Harry.Common.Utils.GetTimeStamp();即可.

示例代码

 IdCreator c=new IdCreator(0,16);   var id=c.Create();

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:c#分布式ID生成器

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址