首页 > 其他分享 >四个id 生成器性能比较记录

四个id 生成器性能比较记录

时间:2023-11-10 13:22:35浏览次数:37  
标签:Nano 记录 生成器 long ID private id ns public

IdGenerator

Seata 优化的雪花算法

Seata基于改良版雪花算法的分布式UUID生成器分析

关于新版雪花算法的答疑

csharp 移植代码

    public class IdGenerator
    {
        private readonly long twepoch = 1588435200000L;
        private const int workerIdBits = 10;
        private const int timestampBits = 41;
        private const int sequenceBits = 12;
        private const int maxWorkerId = ~(-1 << workerIdBits);
        private long workerId;
        private long timestampAndSequence;
        private readonly long timestampAndSequenceMask = ~(-1L << (timestampBits + sequenceBits));

        public static readonly IdGenerator Instance = new IdGenerator(GenerateWorkerId());

        public IdGenerator(long workerId)
        {
            InitTimestampAndSequence();
            InitWorkerId(workerId);
        }

        private void InitTimestampAndSequence()
        {
            long timestamp = GetNewestTimestamp();
            long timestampWithSequence = timestamp << sequenceBits;
            this.timestampAndSequence = timestampWithSequence;
        }

        private void InitWorkerId(long workerId)
        {
            if (workerId > maxWorkerId || workerId < 0)
            {
                string message = string.Format("worker Id can't be greater than {0} or less than 0", maxWorkerId);
                throw new ArgumentException(message);
            }
            this.workerId = workerId << (timestampBits + sequenceBits);
        }

        public long NextId()
        {
            WaitIfNecessary();
            long next = Interlocked.Increment(ref timestampAndSequence);
            long timestampWithSequence = next & timestampAndSequenceMask;
            return workerId | timestampWithSequence;
        }

        public static long NewId()
        {
            return Instance.NextId();
        }

        private void WaitIfNecessary()
        {
            long currentWithSequence = timestampAndSequence;
            long current = currentWithSequence >> sequenceBits;
            long newest = GetNewestTimestamp();
            if (current >= newest)
            {
                Thread.Sleep(5);
            }
        }

        private long GetNewestTimestamp()
        {
            return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - twepoch;
        }

        public static long GenerateWorkerId()
        {
            try
            {
                return GenerateWorkerIdBaseOnK8S();
            }
            catch (Exception)
            {
                try
                {
                    return GenerateWorkerIdBaseOnMac();
                }
                catch (Exception)
                {
                    return GenerateRandomWorkerId();
                }
            }
        }

        public static long GenerateWorkerIdBaseOnMac()
        {
            IEnumerable<NetworkInterface> all = NetworkInterface.GetAllNetworkInterfaces();
            foreach (NetworkInterface networkInterface in all)
            {
                bool isLoopback = networkInterface.NetworkInterfaceType == NetworkInterfaceType.Loopback;
                //bool isVirtual = networkInterface.;
                //if (isLoopback || isVirtual)
                if (isLoopback)
                {
                    continue;
                }
                byte[] mac = networkInterface.GetPhysicalAddress().GetAddressBytes();
                return ((mac[4] & 0B11) << 8) | (mac[5] & 0xFF);
            }
            throw new Exception("no available mac found");
        }

        public static long GenerateWorkerIdBaseOnK8S()
        {
            return GenerateWorkerIdBaseOnString(Environment.GetEnvironmentVariable("K8S_POD_ID"));
        }

        public static long GenerateWorkerIdBaseOnString(string str)
        {
            ArgumentNullException.ThrowIfNull(str, nameof(str));
            int hashValue = 0;
            int cc = 2 << (workerIdBits - 1);
            foreach (char c in str)
            {
                hashValue = (hashValue * 31 + c) % cc;
            }
            return hashValue + 1;
        }

        public static long GenerateRandomWorkerId()
        {
            return Random.Shared.NextInt64(maxWorkerId + 1);
        }
    }

YitIdHelper

开源库 https://github.com/yitter/IdGenerator

❄ 这是优化的雪花算法(雪花漂移),它生成的ID更短、速度更快。

❄ 支持 k8s 等容器环境自动扩容(自动注册 WorkerId),可在单机或分布式环境生成数字型唯一ID。

Guid

https://learn.microsoft.com/zh-cn/dotnet/api/system.guid?view=net-7.0

全局唯一标识符(GUID,Globally Unique Identifier)是一种由算法生成的二进制长度为128位的数字标识符。GUID主要用于在拥有多个节点、多台计算机的网络或系统中。

Nanoid

开源库 https://github.com/codeyu/nanoid-net

一个小巧、安全、URL友好、唯一的字符串ID生成器。

“一个惊人的无意义的完美主义水平,这简直让人无法不敬佩。”

  • 小巧. 130字节 (经过压缩和gzip处理)。没有依赖。Size Limit 控制大小。
  • 安全. 它使用硬件随机生成器。可在集群中使用。
  • 紧凑. 它使用比 UUID(A-Za-z0-9_-)更大的字母表。因此,ID 大小从36个符号减少到21个符号。
  • 可移植. Nano ID 已被移植到 20种编程语言。

Nano ID 与 UUID v4 (基于随机数) 相当。 它们在 ID 中有相似数量的随机位 (Nano ID 为126,UUID 为122),因此它们的碰撞概率相似::

要想有十亿分之一的重复机会, 必须产生103万亿个版本4的ID.

Nano ID 和 UUID v4之间有两个主要区别:

Nano ID 使用更大的字母表,所以类似数量的随机位 被包装在21个符号中,而不是36个。
Nano ID 代码比 uuid/v4 包少 4倍: 130字节而不是423字节.

性能测试代码

[AllStatisticsColumn]
public class IdGeneratorTest
{
    public IdGeneratorTest()
    {
        var options = new IdGeneratorOptions()
        {
            WorkerId = 55,
            WorkerIdBitLength = 6,
            SeqBitLength = 12,
        };
        YitIdHelper.SetIdGenerator(options);
    }

    [Benchmark]
    public long IdGeneratorNewId() => IdGenerator.NewId();


    [Benchmark]
    public long YitIdHelperNextId() => YitIdHelper.NextId();

    [Benchmark]
    public string NewGuid() => Guid.NewGuid().ToString();

    [Benchmark]
    public string NanoidGenerate() => Nanoid.Generate();
}

结果


BenchmarkDotNet v0.13.10, Windows 11 (10.0.22000.2538/21H2/SunValley)
Intel Core i7-10700 CPU 2.90GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK 7.0.403
  [Host]     : .NET 6.0.24 (6.0.2423.51814), X64 RyuJIT AVX2
  DefaultJob : .NET 6.0.24 (6.0.2423.51814), X64 RyuJIT AVX2


Method Mean Error StdDev StdErr Median Min Q1 Q3 Max Op/s
IdGeneratorNewId 243.3 ns 1.33 ns 1.25 ns 0.32 ns 243.0 ns 241.42 ns 242.32 ns 244.3 ns 246.1 ns 4,109,814.4
YitIdHelperNextId 241.7 ns 66.08 ns 194.85 ns 19.48 ns 430.2 ns 43.51 ns 43.83 ns 431.8 ns 432.7 ns 4,137,225.0
NewGuid 179.5 ns 3.63 ns 6.06 ns 1.01 ns 177.1 ns 173.10 ns 175.06 ns 182.5 ns 193.3 ns 5,572,366.5
NanoidGenerate 188.6 ns 4.30 ns 12.21 ns 1.27 ns 185.1 ns 174.49 ns 179.40 ns 195.5 ns 219.8 ns 5,301,348.8

标签:Nano,记录,生成器,long,ID,private,id,ns,public
From: https://www.cnblogs.com/fs7744/p/17823881.html

相关文章

  • spring复习:(57)PropertyOverrideConfigurer用法及工作原理
    一、属性配置文件dataSource.url=jdbc:mysql://xxx.xxx.xxx.xxx/testdataSource.username=rootdataSource.password=xxxxxxdataSource.driverClassName=com.mysql.jdbc.Driver#dataSource.type=com.alibaba.druid.pool.DruidDataSource二、spring配置文件<?xmlversion="1.0&quo......
  • idea常用设置
    1、设置SceneBuilder下载安装SceneBuilder--idea--settings--languages&frameworks---javafx--pathto SceneBuilder:D:\JetBrains\SceneBuilder\SceneBuilder.exe。即可选择fxml文件右键打开可视化编辑窗口。2、设置本地安装的maven下载安装maven--id......
  • Android并发编程高级面试题汇总(含详细解析 十四)
    Android并发编程高级面试题汇总最全最细面试题讲解持续更新中......
  • 【零基础速领】全套Android零基础入门指南(PDF文档+全套视频),Android Studio安装教程
    Android开发的入门可分成两个大的阶段,第一个语言的学习,第二个Android框架的学习。语言的学习Android开发目前主要有两种语言,java和kotlin,kotlin是目前google官方的首推语言,但个人还是建议先学java,因为至少在未来的几年内,公司的项目肯定是还会有大量的java代码,你至少需要能看懂,能去......
  • 2023金九银十Android程序员面试题参考指南!
    前言还有不到一个礼拜就是金九银十招聘高峰期了,在这里分享一份《Android面试题汇总》这些面试题都是互联网大厂真实流出的面试内容,每个问题都附带完整详细的答案,不像网上的那些资料三教九流有的甚至还没答案,这些面试题都是我也是整理出来的精品资料。希望能给那些有需要朋友在求职......
  • 学Android不知道这些,毕业=失业!
    很多专科毕业,Android不好找工作的同学,看过来!!这样一个竞争激烈的市场环境下,想要成为一名优秀的Android开发者,仅仅依靠课本上的知识是远远不够的。那么,作为一名Android开发学习者,有哪些知识是我们必须掌握的呢?1.掌握扎实的基本功俗话说:基础不牢,地动山摇。作为应届生,由于没有什么实际......
  • Android入门教程 | Fragment 基础概念
    什么是Fragment?Fragment,直译为“碎片”,“片段”。Fragment表示FragmentActivity中的行为或界面的一部分。可以在一个Activity中组合多个片段,从而构建多窗格界面,并在多个Activity中重复使用某个片段。可以将片段视为Activity的模块化组成部分,它具有自己的生命周期,能接收自......
  • Android零基础入门 | 广播机制 Broadcast
    Android应用可以通过广播从系统或其他App接收或发送消息。类似于订阅-发布设计模式。当某些事件发生时,可以发出广播。系统在某些状态改变时会发出广播,例如开机、充电。App也可发送自定义广播。广播可用于应用间的通讯,是IPC的一种方式。广播的种类广播的种类也可以看成是广播的属性......
  • Node opensslErrorStack 错误解决方法记录
    从Git仓库中下载了一个老项目,使用npminstall安装后没有问题,当我使用npmrundev的时候遇到了OpenSSL相关错误,例如opensslErrorStack:['error:03000086:digitalenveloperoutines::initializationerror']网上找了一下相关信息,然后顺利解决了,记录分享给大家问题原因:这种错......
  • 设置成员操作符--inside
     设置成员操作符–insideSystemVerilog增加了一个检测是否集合中–员的操作符,这个操作符的关键字是inside。logic[2:0]a;if(ainside{3'b001,3'b010,3'b100})//等价if((a==3'b001)||(a==3'b010)||(a==3'b100))...使用inside操作符可以方便的比较一个数值和多个可能值......