C# Guid长度雪花(snowflake)简单生成器

标准的long雪花长度为64bit,还要浪费1bit,然后41位时间,10位workid,12位序列

guid长度128位,64位完整的时间tick,32位workid,32位序列,可谓随便用满非常豪华

也就是系统里可以根据需要有的地方存随机guid,有的地方存雪花guid,随便换

随后还有提取时间的方法,由于是64位完整时间,直接拿出来转时间就好了

 

这个类参考别人的代码,如果需要设计更完善的guid雪花,可以在github上或者nuget上找newid这个项目,老外写好的更完善的做法

 

guid长度雪花继承雪花id所有优点和特点,只是长度略长

可以用guid存储,以往习惯guid的人没有压力,对guid支持较好的数据库就能支持好guid雪花,mysql不行

一个项目不同表可以使用不同策略,有的用guid,有的用雪花guid,按需使用,也更方便导数据

时间储存的完整long,可以提取出完整时间,时间照样从0年开始,再老的数据也可以导,只要按时间顺序,自己传个时间给next方法

序列号数量充足,不会动不动就加1秒,workid更长,可以分段放不同的内容

 

 

 

public class GuidSnowFlakeGenerator
    {
        readonly uint _c;
        int _a;
        int _b;
        long _lastTick;
        uint _sequence;

        SpinLock _spinLock;

        public GuidSnowFlakeGenerator(uint workId)
        {
            _spinLock = new SpinLock(false);
            _c = workId;
        }

        public Guid Next()
        {
            var ticks = DateTime.UtcNow.Ticks;

            int a;
            int b;
            uint sequence;

            var lockTaken = false;
            try
            {
                _spinLock.Enter(ref lockTaken);

                if (ticks > _lastTick)
                    UpdateTimestamp(ticks);
                else if (_sequence == uint.MaxValue)
                    UpdateTimestamp(_lastTick + 1);

                sequence = _sequence++;

                a = _a;
                b = _b;
            }
            finally
            {
                if (lockTaken)
                    _spinLock.Exit();
            }

            var s = sequence;
            byte[] bytes = new byte[16];
            bytes[0] = (byte)(a >> 24);
            bytes[1] = (byte)(a >> 16);
            bytes[2] = (byte)(a >> 8);
            bytes[3] = (byte)a;
            bytes[4] = (byte)(b >> 24);
            bytes[5] = (byte)(b >> 16);
            bytes[6] = (byte)(b >> 8);
            bytes[7] = (byte)b;
            bytes[8] = (byte)(_c >> 24);
            bytes[9] = (byte)(_c >> 16);
            bytes[10] = (byte)(_c >> 8);
            bytes[11] = (byte)(_c);
            bytes[12] = (byte)(s >> 24);
            bytes[13] = (byte)(s >> 16);
            bytes[14] = (byte)(s >> 8);
            bytes[15] = (byte)(s >> 0);

            return new Guid(bytes);
        }


        void UpdateTimestamp(long tick)
        {
            _b = (int)(tick & 0xFFFFFFFF);
            _a = (int)(tick >> 32);

            _sequence = 0;
            _lastTick = tick;
        }

        public static DateTime GetTime(Guid guid)
        {
            var bytes = guid.ToByteArray();
            long tick = (long)bytes[0] << 56;
            tick += (long)bytes[1] << 48;
            tick += (long)bytes[2] << 40;
            tick += (long)bytes[3] << 32;
            tick += (long)bytes[3] << 24;
            tick += (long)bytes[3] << 16;
            tick += (long)bytes[3] << 8;
            tick += (long)bytes[3];
            return new DateTime(tick, DateTimeKind.Utc);
        }
    }

 

 

using System;
using System.Threading;

//适配顺序,在支持uuid的数据库中可以按时间排序
public class GuidSnowFlakeGenerator
{
    readonly uint _c;
    int _a;
    int _b;
    long _lastTick;
    uint _sequence;

    SpinLock _spinLock;

    public GuidSnowFlakeGenerator(uint workId)
    {
        _spinLock = new SpinLock(false);
        _c = workId;
    }

    public GuidSnowFlakeGenerator(bool randomWorkId)
    {
        _spinLock = new SpinLock(false);
        uint workId = BitConverter.ToUInt32(Guid.NewGuid().ToByteArray(), 0);
        _c = workId;
    }

    public Guid Next()
    {
        return Next(DateTime.UtcNow);
    }
    public Guid Next(DateTime dataTime)
    {
        var ticks = dataTime.ToUniversalTime().Ticks;

        int a;
        int b;
        uint sequence;

        var lockTaken = false;
        try
        {
            _spinLock.Enter(ref lockTaken);

            if (ticks > _lastTick)
                UpdateTimestamp(ticks);
            else if (_sequence == uint.MaxValue)
                UpdateTimestamp(_lastTick + 1);

            sequence = _sequence++;

            a = _a;
            b = _b;
        }
        finally
        {
            if (lockTaken)
                _spinLock.Exit();
        }

        var s = sequence;
        byte[] bytes = new byte[16];
        bytes[0] = (byte)a;
        bytes[1] = (byte)(a >> 8);
        bytes[2] = (byte)(a >> 16);
        bytes[3] = (byte)(a >> 24);
        bytes[4] = (byte)(b >> 16);
        bytes[5] = (byte)(b >> 24);
        bytes[6] = (byte)b;
        bytes[7] = (byte)(b >> 8);
        bytes[8] = (byte)(_c >> 24);
        bytes[9] = (byte)(_c >> 16);
        bytes[10] = (byte)(_c >> 8);
        bytes[11] = (byte)(_c);
        bytes[12] = (byte)(s >> 24);
        bytes[13] = (byte)(s >> 16);
        bytes[14] = (byte)(s >> 8);
        bytes[15] = (byte)(s >> 0);

        return new Guid(bytes);
    }


    void UpdateTimestamp(long tick)
    {
        _b = (int)(tick & 0xFFFFFFFF);
        _a = (int)(tick >> 32);

        _sequence = 0;
        _lastTick = tick;
    }

    /// <summary>
    /// 和Guid.ToString一样的顺序输出,方便排序
    /// </summary>
    /// <param name="guid"></param>
    /// <returns></returns>
    public static byte[] ToFixedByteArray(Guid guid)
    {
        var bytes = guid.ToByteArray();
        var rtnbytes = new byte[16];

        rtnbytes[0] = bytes[3];
        rtnbytes[1] = bytes[2];
        rtnbytes[2] = bytes[1];
        rtnbytes[3] = bytes[0];
        rtnbytes[4] = bytes[5];
        rtnbytes[5] = bytes[4];
        rtnbytes[6] = bytes[7];
        rtnbytes[7] = bytes[6];
        Array.Copy(bytes, 8, rtnbytes, 8, 8);

        return rtnbytes;
    }

    public static DateTime GetTime(Guid guid)
    {
        var bytes = guid.ToByteArray();
        var rtnbytes = new byte[8];

        rtnbytes[0] = bytes[6];
        rtnbytes[1] = bytes[7];
        rtnbytes[2] = bytes[4];
        rtnbytes[3] = bytes[5];
        rtnbytes[4] = bytes[0];
        rtnbytes[5] = bytes[1];
        rtnbytes[6] = bytes[2];
        rtnbytes[7] = bytes[3];
        long tick = BitConverter.ToInt64(rtnbytes, 0);
        return new DateTime(tick, DateTimeKind.Utc);
    }
}

 

posted @ 2020-11-19 10:12  咖喱gg  阅读(1501)  评论(0编辑  收藏  举报