首頁  >  文章  >  类库下载  >  c#分散式ID產生器

c#分散式ID產生器

高洛峰
高洛峰原創
2016-11-04 16:48:472001瀏覽

簡介

這個是根據twitter的snowflake來寫的.這裡有中文的介紹.

c#分散式ID產生器


如上圖所示,一個64位ID,除了最左邊的符號位不用固定為左邊符號位而以確保產生的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>
        /// <param name="instanceID">实例编号(0-1023)</param>
        /// <param name="indexBitLength">索引可用位数(1-32).每秒可生成ID数等于2的indexBitLength次方.大并发情况下,当前秒内ID数达到最大值时,将使用下一秒的时间戳,不影响获取ID.</param>
        /// <param name="initTimestamp">初始化时间戳,精确到秒.当之前同一实例生成ID的timestamp值大于当前时间的时间戳时,
        /// 有可能会产生重复ID(如持续一段时间的大并发请求).设置initTimestamp比最后的时间戳大一些,可避免这种问题</param>
        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 < 1)
            {                this.indexBitLength = 1;
            }            else if (indexBitLength > 32)            {                this.indexBitLength = 32;
            }            else
            {                this.indexBitLength = indexBitLength;
            }
            tsMax = Convert.ToInt64(new string(&#39;1&#39;, 53 - indexBitLength), 2);
            indexMax = Convert.ToInt64(new string(&#39;1&#39;, indexBitLength), 2);            if (initTimestamp != null)
            {                this.timestamp = initTimestamp.Value;
            }
        }        /// <summary>
        /// 默认每实例每秒生成65536个ID,从1970年1月1日起,累计可使用4358年
        /// </summary>
        /// <param name="instanceID">实例编号(0-1023)</param>
        public IdCreator(int instanceID) : this(instanceID, 16)        {

        }        /// <summary>
        /// 默认每秒生成65536个ID,从1970年1月1日起,累计可使用4358年
        /// </summary>
        public IdCreator() : this(-1)        {

        }        /// <summary>
        /// 生成64位ID
        /// </summary>
        /// <returns></returns>
        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 < ts)
                {
                    timestamp = ts;
                    index = 0;
                }                else
                {                    if (index > 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();


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn