public class SnowFlake { /// <summary> /// 总机器位数 /// </summary> private static readonly int WorkBits = 5; /// <summary> /// 自增序列号位数 /// </summary> private static readonly int SequenceBits = 16; /// <summary> /// 序列号最大值 0开始 /// </summary> private static readonly long SequenceMax = 1L << SequenceBits; /// <summary> /// 服务器最大值 /// </summary> private static readonly long WorkMax = 1L << WorkBits; /// <summary> /// 当前机器号 0-WorkMax /// </summary> private static long CurrentWorkId = 0; /// <summary> /// 加锁对象 /// </summary> private readonly object objlock = new object(); /// <summary> /// 记录上次时间戳 /// </summary> private static long LastTime; /// <summary> /// 当前序列号 0开始 /// </summary> private static long CurrentSequence = -1; public SnowFlake(int _CurrentWorkId) { CurrentWorkId = _CurrentWorkId; Console.WriteLine(SequenceMax); } /// <summary> /// 自定义时间戳 /// </summary> /// <returns></returns> private long GetTime() { return (long)(DateTime.UtcNow - new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds; } /// <summary> /// 获取ID /// </summary> /// <returns></returns> public long NextId() { lock (objlock) { if (CurrentWorkId >= WorkMax) { throw new Exception($"机器码不能大于最大机器码值{WorkMax}"); } var time = GetTime(); //同秒内序列号自增 if (time == LastTime) { //序列号超出最大 等待下一个时间点 if (CurrentSequence >= SequenceMax) { //等待下一个时间点 while (time == LastTime) { time = GetTime(); } CurrentSequence = -1; LastTime = time; } } else { //不同秒 重新自增 CurrentSequence = -1; LastTime = time; } CurrentSequence++; //Console.WriteLine(DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss fff")); //Console.WriteLine(CurrentSequence); var num = (WorkBits + SequenceBits); return time << num | CurrentWorkId << SequenceBits | CurrentSequence; } } }
以上代码为个人理解写法,若有不足,请指正。
实际的算法为 1个0bit+41bit时间戳+10bit机器码+12bit序列号; 最终得到的是64bit的二进制 也就是能支持int64最大值,可支持单机器每秒400多W的ID生成;
但js的最大Number类型是53bit,且常用系统也达不到这么多并发,所以参考了廖雪峰老师的意见 修改为
32bit的秒级时间戳(现计算结果为31bit)+5bit的机器码+16bit的序列号 共53bit,而且时间戳未使用1970默认算法,采用了自定义年份,以上代码可支持最大2^5=32个机器 每台机器2^16=65535个ID生成。
SnowFlake算法其他理解参考 https://www.cnblogs.com/firstdream/p/9055771.html,
查看int的bit可用 Convert.ToString(num, 2);查看
<< 左偏移 右边补齐0
| 或算法