最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C# .NET實現(xiàn)雪花ID生成器的具體方案

 更新時間:2026年01月05日 08:33:19   作者:東百牧碼人  
雪花ID是Twitter開源的分布式ID生成算法,核心是將64位長整型ID按規(guī)則拆分,保證全局唯一且趨勢遞增,你希望在.NET中實現(xiàn)一個完整、線程安全且能處理時鐘回?fù)軉栴}的雪花ID算法,下面先講解核心結(jié)構(gòu),再給出可直接使用的.NET實現(xiàn)代碼,需要的朋友可以參考下

引言

你希望在.NET中實現(xiàn)一個完整、線程安全且能處理時鐘回?fù)軉栴}的雪花ID(Snowflake)算法,用于分庫分表場景下生成全局唯一的分布式ID,避免不同庫/表的主鍵重復(fù)。

雪花ID是Twitter開源的分布式ID生成算法,核心是將64位長整型ID按規(guī)則拆分,保證全局唯一且趨勢遞增。下面先講解核心結(jié)構(gòu),再給出可直接使用的.NET實現(xiàn)代碼。

一、雪花ID核心結(jié)構(gòu)(64位long型)

位段長度作用
符號位1位固定為0(保證ID為正數(shù))
時間戳位41位記錄生成ID的毫秒級時間戳(相對于一個起始時間),可支持約69年(2^41-1)
機(jī)器/節(jié)點位10位分為5位數(shù)據(jù)中心ID + 5位機(jī)器ID,最多支持1024個節(jié)點部署
序列號位12位同一毫秒內(nèi)的自增序列,每毫秒最多生成4096個ID(2^12=4096)

二、.NET實現(xiàn)雪花ID生成器

以下實現(xiàn)包含線程安全、時鐘回?fù)軝z測、參數(shù)合法性校驗,可直接在生產(chǎn)環(huán)境使用:

using System;
using System.Threading;

/// <summary>
/// 雪花ID生成器(線程安全、支持時鐘回?fù)軝z測)
/// </summary>
public class SnowflakeIdGenerator
{
    #region 常量定義
    // 起始時間戳(UTC時間:2024-01-01 00:00:00),可自行調(diào)整,建議使用項目上線前的時間
    private const long Epoch = 1704067200000L;

    // 各部分的位長度
    private const int TimestampBits = 41; // 時間戳位長度
    private const int DataCenterIdBits = 5; // 數(shù)據(jù)中心ID位長度
    private const int MachineIdBits = 5; // 機(jī)器ID位長度
    private const int SequenceBits = 12; // 序列號位長度

    // 最大值(位運算計算)
    private const long MaxDataCenterId = (1L << DataCenterIdBits) - 1; // 31
    private const long MaxMachineId = (1L << MachineIdBits) - 1; // 31
    private const long MaxSequence = (1L << SequenceBits) - 1; // 4095

    // 位移量
    private const int MachineIdShift = SequenceBits; // 12
    private const int DataCenterIdShift = SequenceBits + MachineIdBits; // 17
    private const int TimestampShift = SequenceBits + MachineIdBits + DataCenterIdBits; // 22
    #endregion

    #region 私有字段
    private readonly long _dataCenterId; // 數(shù)據(jù)中心ID
    private readonly long _machineId; // 機(jī)器ID
    private long _lastTimestamp = -1L; // 上一次生成ID的時間戳
    private long _sequence = 0L; // 當(dāng)前毫秒內(nèi)的序列號
    private readonly object _lockObj = new(); // 鎖對象(保證線程安全)
    #endregion

    /// <summary>
    /// 構(gòu)造函數(shù)
    /// </summary>
    /// <param name="dataCenterId">數(shù)據(jù)中心ID(0-31)</param>
    /// <param name="machineId">機(jī)器ID(0-31)</param>
    /// <exception cref="ArgumentException">參數(shù)超出范圍時拋出</exception>
    public SnowflakeIdGenerator(long dataCenterId, long machineId)
    {
        // 校驗參數(shù)合法性
        if (dataCenterId < 0 || dataCenterId > MaxDataCenterId)
        {
            throw new ArgumentException($"數(shù)據(jù)中心ID必須在0-{MaxDataCenterId}之間", nameof(dataCenterId));
        }
        if (machineId < 0 || machineId > MaxMachineId)
        {
            throw new ArgumentException($"機(jī)器ID必須在0-{MaxMachineId}之間", nameof(machineId));
        }

        _dataCenterId = dataCenterId;
        _machineId = machineId;
    }

    /// <summary>
    /// 生成下一個雪花ID
    /// </summary>
    /// <returns>全局唯一的雪花ID</returns>
    /// <exception cref="Exception">時鐘回?fù)艹鋈萑谭秶鷷r拋出</exception>
    public long NextId()
    {
        lock (_lockObj) // 加鎖保證多線程安全
        {
            // 1. 獲取當(dāng)前時間戳(毫秒)
            long currentTimestamp = GetCurrentTimestamp();

            // 2. 處理時鐘回?fù)軉栴}
            if (currentTimestamp < _lastTimestamp)
            {
                long timeDiff = _lastTimestamp - currentTimestamp;
                // 容忍500ms內(nèi)的時鐘回?fù)埽ǖ却钡綍r間追上)
                if (timeDiff <= 500)
                {
                    // 自旋等待,直到時間戳追上上次的時間戳
                    while (currentTimestamp < _lastTimestamp)
                    {
                        currentTimestamp = GetCurrentTimestamp();
                    }
                }
                else
                {
                    // 超出容忍范圍,拋出異常(避免ID重復(fù))
                    throw new Exception($"時鐘回?fù)墚惓#‘?dāng)前時間戳:{currentTimestamp},上次時間戳:{_lastTimestamp},差值:{timeDiff}ms");
                }
            }

            // 3. 處理同一毫秒內(nèi)的序列號
            if (currentTimestamp == _lastTimestamp)
            {
                // 序列號自增,超過最大值則等待下一毫秒
                _sequence = (_sequence + 1) & MaxSequence;
                if (_sequence == 0)
                {
                    // 自旋等待下一毫秒
                    while (currentTimestamp <= _lastTimestamp)
                    {
                        currentTimestamp = GetCurrentTimestamp();
                    }
                }
            }
            else
            {
                // 新的毫秒,序列號重置為0
                _sequence = 0;
            }

            // 4. 更新上次時間戳
            _lastTimestamp = currentTimestamp;

            // 5. 拼接各部分生成最終ID
            return ((currentTimestamp - Epoch) << TimestampShift) // 時間戳部分
                   | (_dataCenterId << DataCenterIdShift) // 數(shù)據(jù)中心ID部分
                   | (_machineId << MachineIdShift) // 機(jī)器ID部分
                   | _sequence; // 序列號部分
        }
    }

    /// <summary>
    /// 獲取當(dāng)前UTC時間戳(毫秒)
    /// </summary>
    /// <returns>毫秒級時間戳</returns>
    private long GetCurrentTimestamp()
    {
        return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
    }

    #region 便捷方法(可選)
    /// <summary>
    /// 生成雪花ID的字符串形式
    /// </summary>
    /// <returns>ID字符串</returns>
    public string NextIdString()
    {
        return NextId().ToString();
    }

    /// <summary>
    /// 解析雪花ID,返回各部分信息(用于調(diào)試)
    /// </summary>
    /// <param name="id">雪花ID</param>
    /// <returns>解析后的信息</returns>
    public (DateTime GenerateTime, long DataCenterId, long MachineId, long Sequence) ParseId(long id)
    {
        long timestamp = (id >> TimestampShift) + Epoch;
        DateTime generateTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(timestamp);
        long dataCenterId = (id >> DataCenterIdShift) & MaxDataCenterId;
        long machineId = (id >> MachineIdShift) & MaxMachineId;
        long sequence = id & MaxSequence;

        return (generateTime.ToLocalTime(), dataCenterId, machineId, sequence);
    }
    #endregion
}

三、使用示例

class Program
{
    static void Main(string[] args)
    {
        // 初始化生成器(數(shù)據(jù)中心ID=1,機(jī)器ID=1,根據(jù)實際部署環(huán)境調(diào)整)
        var idGenerator = new SnowflakeIdGenerator(1, 1);

        // 單線程生成ID
        long id1 = idGenerator.NextId();
        Console.WriteLine($"生成的雪花ID:{id1}");

        // 解析ID(調(diào)試用)
        var parseResult = idGenerator.ParseId(id1);
        Console.WriteLine($"生成時間:{parseResult.GenerateTime}");
        Console.WriteLine($"數(shù)據(jù)中心ID:{parseResult.DataCenterId}");
        Console.WriteLine($"機(jī)器ID:{parseResult.MachineId}");
        Console.WriteLine($"序列號:{parseResult.Sequence}");

        // 多線程測試(驗證線程安全)
        Parallel.For(0, 1000, i =>
        {
            long id = idGenerator.NextId();
            Console.WriteLine($"線程{Thread.CurrentThread.ManagedThreadId}生成ID:{id}");
        });
    }
}

四、關(guān)鍵說明

  1. 起始時間戳(Epoch):建議設(shè)置為項目上線前的時間(如示例中的2024-01-01),可延長ID使用周期(默認(rèn)能用到2093年)。
  2. 機(jī)器/數(shù)據(jù)中心ID:部署時需保證每個節(jié)點的(數(shù)據(jù)中心ID+機(jī)器ID)唯一(比如通過配置文件/環(huán)境變量設(shè)置),避免不同節(jié)點生成重復(fù)ID。
  3. 時鐘回?fù)芴幚?/strong>:代碼中容忍500ms內(nèi)的時鐘回?fù)埽ㄗ孕却?,超出則拋異常,可根據(jù)業(yè)務(wù)調(diào)整容忍閾值。
  4. 性能:單節(jié)點每秒可生成約400萬+ ID(1ms生成4096個,1秒=1000ms → 4096*1000=4,096,000),滿足絕大多數(shù)業(yè)務(wù)場景。

總結(jié)

  1. 雪花ID核心是通過位運算將時間戳、機(jī)器ID、序列號拼接成64位唯一ID,保證全局唯一且趨勢遞增;
  2. 實現(xiàn)時必須保證線程安全(加鎖)和時鐘回?fù)軝z測(避免ID重復(fù));
  3. 使用時需保證每個節(jié)點的機(jī)器/數(shù)據(jù)中心ID唯一,起始時間戳建議根據(jù)項目實際調(diào)整。

這個實現(xiàn)可直接集成到你的.NET分庫分表項目中,作為分布式主鍵生成方案。

到此這篇關(guān)于C# .NET實現(xiàn)雪花ID生成器的具體方案的文章就介紹到這了,更多相關(guān)C# .NET雪花ID生成器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#8 的模式匹配實現(xiàn)

    C#8 的模式匹配實現(xiàn)

    這篇文章主要介紹了C#8 的模式匹配實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • 通過C#調(diào)用Windows?API的具體方法

    通過C#調(diào)用Windows?API的具體方法

    在開發(fā)系統(tǒng)監(jiān)控工具、性能分析器或自動化管理程序時,Windows?API?是你與操作系統(tǒng)對話的橋梁,通過C#調(diào)用Windows?API可以直接訪問系統(tǒng)底層數(shù)據(jù)、實現(xiàn)注冊表讀寫與電源狀態(tài)監(jiān)控以及無需額外依賴,純原生代碼實現(xiàn),所以本文給大家介紹了具體的調(diào)用方法,需要的朋友可以參考下
    2025-08-08
  • C# 忽略大小寫進(jìn)行字符串比較

    C# 忽略大小寫進(jìn)行字符串比較

    這篇文章主要介紹了C# 字符串比較忽略大小寫的方法,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下
    2021-02-02
  • WPF彈出右鍵菜單時判斷鼠標(biāo)是否選中該項

    WPF彈出右鍵菜單時判斷鼠標(biāo)是否選中該項

    這篇文章介紹了WPF彈出右鍵菜單時判斷鼠標(biāo)是否選中該項的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • C#實現(xiàn)餐飲管理系統(tǒng)

    C#實現(xiàn)餐飲管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C#實現(xiàn)餐飲管理系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • C#實現(xiàn)梳排序的使用示例

    C#實現(xiàn)梳排序的使用示例

    梳排序算法是一種改進(jìn)的冒泡排序算法,它通過調(diào)整冒泡排序的間隔來提高排序的效率,本文主要介紹了C#實現(xiàn)梳排序的使用示例,感興趣的可以了解一下
    2023-11-11
  • C#異常處理的一些經(jīng)驗和技巧

    C#異常處理的一些經(jīng)驗和技巧

    本文是異常處理經(jīng)驗性的文章,其實跟C#關(guān)系也不大。比較適合剛剛熟悉異常語法,而缺乏實戰(zhàn)的讀者。當(dāng)然,經(jīng)驗老練的讀者也可指出不足、給予意見、補(bǔ)充說明,一起完善文章,分享更多知識與經(jīng)驗
    2014-03-03
  • C#中const 和 readonly 修飾符的用法詳解

    C#中const 和 readonly 修飾符的用法詳解

    這篇文章主要介紹了C#中const 和 readonly 修飾符的用法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-09-09
  • C#使用ffmpeg實現(xiàn)將圖片保存為mp4視頻

    C#使用ffmpeg實現(xiàn)將圖片保存為mp4視頻

    FFmpeg是一個開源的跨平臺多媒體處理工具,它提供了強(qiáng)大的功能,包括頻和視頻編碼、解碼、轉(zhuǎn)碼等,本文我們將使用FFmpeg實現(xiàn)將圖片保存為mp4視頻,感興趣的可以了解下
    2024-11-11
  • C#線程定義和使用方法詳解

    C#線程定義和使用方法詳解

    這篇文章主要介紹了C#Thread類的基本用法,如何定義一個線程類,為線程傳遞參數(shù)的方法,詳解看下文
    2013-11-11

最新評論

嘉荫县| 忻城县| 安龙县| 抚顺市| 南乐县| 汤原县| 凭祥市| 山西省| 电白县| 文安县| 孟津县| 新巴尔虎左旗| 万盛区| 大洼县| 安吉县| 行唐县| 章丘市| 温州市| 秭归县| 富阳市| 鄂伦春自治旗| 永新县| 霍邱县| 崇阳县| 凤城市| 兰考县| 河东区| 桐乡市| 贵州省| 张家川| 正阳县| 全南县| 克山县| 格尔木市| 伊通| 徐汇区| 商南县| 芜湖市| 榕江县| 昌江| 肇州县|