程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 【高性能】生成唯一時間戳ID,1毫秒預計能生成1000個,毫秒1000

【高性能】生成唯一時間戳ID,1毫秒預計能生成1000個,毫秒1000

編輯:C#入門知識

【高性能】生成唯一時間戳ID,1毫秒預計能生成1000個,毫秒1000


凡事涉及到高性能貌似都是高大上的東西,所以嘛我也試試;其實這個時間戳ID的生成主要為了解決我們公司內部的券號生成,估計有小伙伴認為券號生成有這麼麻煩嘛,搞個自增ID完全可以用起來,或者時間取毫微米時間戳等。

如果以上真是這樣簡單的話,那我要說道說道;首先自增ID資源耗盡的時候,特別禮券號生成的越頻繁,畢竟bigInt也有耗盡那天(當然如果有更長數字字段就是慢慢耗呗),而且依靠數據庫進行被動生成,在有些業務上比較軟肋;我還有一個同事說搞一張表定時去自增生成ID,這樣就能隨時取已經存在的ID資源數據,我只能說這是一種笨辦法,而且你都不知道外部業務對券號的需要量有多少,萬一立馬要個1000萬,你來得及?

還有就是毫微米時間戳也是會出問題,因為在多並發請求下也會大概率出現同樣ID,大家不信可以去試試,想想我們的CPU運算有多快;當然防止重復可以考慮休眠例如一毫秒,但這樣就會丟失性能,想想雪花算法一毫秒能產生4095個不重復ID,我們好歹也可以向它學習吧,以上說了這麼多少就明白了這個要求也是蠻苛刻的,當中我也想過用雪花算法,但由於生成的ID比較長(後面我會說為什麼不適宜)!

下面來看看我對這個唯一時間戳ID生成的代碼算法,借鑒了點雪花算法:

   /// <summary>
    /// 時間戳ID
    /// </summary>
    public class TimestampID
    {
        private long _lastTimestamp;
        private long _sequence; //計數從零開始
        private readonly DateTime? _initialDateTime;
        private static TimestampID _timestampID;
        private const int MAX_END_NUMBER = 9999;

        private TimestampID(DateTime? initialDateTime)
        {
            _initialDateTime = initialDateTime;
        }

        /// <summary>
        /// 獲取單個實例對象
        /// </summary>
        /// <param name="initialDateTime">最初時間,與當前時間做個相差取時間戳</param>
        /// <returns></returns>
        public static TimestampID GetInstance(DateTime? initialDateTime = null)
        {
            if (_timestampID == null) Interlocked.CompareExchange(ref _timestampID, new TimestampID(initialDateTime), null);
            return _timestampID;
        }

        /// <summary>
        /// 最初時間,作用時間戳的相差
        /// </summary>
        protected DateTime InitialDateTime
        {
            get
            {
                if (_initialDateTime == null || _initialDateTime.Value == DateTime.MinValue) return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
                return _initialDateTime.Value;
            }
        }
        /// <summary>
        /// 獲取時間戳ID
        /// </summary>
        /// <returns></returns>
        public string GetID()
        {
            long temp;
            var timestamp = GetUniqueTimeStamp(_lastTimestamp, out temp);
            return $"{timestamp}{Fill(temp)}";
        }

        private string Fill(long temp)
        {
            var num = temp.ToString();
            IList<char> chars = new List<char>();
            for (int i = 0; i < MAX_END_NUMBER.ToString().Length - num.Length; i++)
            {
                chars.Add('0');
            }
            return new string(chars.ToArray()) + num;
        }

        /// <summary>
        /// 獲取一個時間戳字符串
        /// </summary>
        /// <returns></returns>
        public long GetUniqueTimeStamp(long lastTimeStamp, out long temp)
        {
            lock (this)
            {
                temp = 1;
                var timeStamp = GetTimestamp();
                if (timeStamp == _lastTimestamp)
                {
                    _sequence = _sequence + 1;
                    temp = _sequence;
                    if (temp >= MAX_END_NUMBER)
                    {
                        timeStamp = GetTimestamp();
                        _lastTimestamp = timeStamp;
                        temp = _sequence = 1;
                    }
                }
                else
                {
                    _sequence = 1;
                    _lastTimestamp = timeStamp;
                }
                return timeStamp;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private long GetTimestamp()
        {
            if (InitialDateTime >= DateTime.Now) throw new Exception("最初時間比當前時間還大,不合理");
            var ts = DateTime.UtcNow - InitialDateTime;
            return (long)ts.TotalMilliseconds;
        }
    }

當中我加了一點補位算法,保證每次出來的ID長度一致,之前提到了是用在禮券號上的,那就應該不能這麼長,後續我又繼續進行了32進制計算,縮短到8-10位左右,但大家估計覺的還是長,那就看取決你把相差時間應該縮短。但如果直接用雪花算法生成的ID進行32位進制縮短也是在10位以上,所以我沒有用到。

對了,忘記說了性能問題,一毫秒預計能生成1000個,呵呵,還算過得去

接下來談談禮券這塊業務,類似我們初創電商公司這種需要去互聯網上大量拉攏會員,所以也相對需要大量的推廣禮券號,如果成熟的電商如京東和天貓等,他們所有禮券都已經綁定到自己會員身上,在使用上根本不用去關注填寫什麼禮券號,也是他們的禮券體系相對完整和成熟,故我們對禮券號的的生成需求也是一塊心病。

下面再說說雪花算法生成的ID,比較適合使用一些流水數據,如果分布式上生成時就需要考慮一台吞吐量好的服務統一生成ID,或者也可以進行多台服務器+負載均衡,當然每台機器出的ID還是需要標識補位(比如機器自定義的編號ID)增加長度防止同一時間重復ID。

以上如有不對之處請留言,大家共同學習進步!!!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved