SnowFlakeNew.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. using System;
  2. using System.Linq;
  3. using System.Net.NetworkInformation;
  4. using Masuit.Tools.DateTimeExt;
  5. using Masuit.Tools.Strings;
  6. namespace Masuit.Tools.Systems;
  7. /// <summary>
  8. /// 改良版雪花id
  9. /// </summary>
  10. public class SnowFlakeNew
  11. {
  12. private readonly long _workerId; //机器ID
  13. private const long Twepoch = 1692079923000L; //唯一时间随机量
  14. private static long Offset = 7783685984256L; //起始偏移量
  15. private static long _sequence;
  16. private const int SequenceBits = 12; //计数器字节数,10个字节用来保存计数码
  17. private const long SequenceMask = -1L ^ -1L << SequenceBits; //一微秒内可以产生计数,如果达到该值则等到下一微妙在进行生成
  18. private static long _lastTimestamp = -1L;
  19. private static readonly object LockObj = new object();
  20. private static NumberFormater _numberFormater = new NumberFormater(36);
  21. private static SnowFlakeNew _snowFlake;
  22. /// <summary>
  23. /// 获取一个新的id
  24. /// </summary>
  25. public static string NewId => GetInstance().GetUniqueId();
  26. /// <summary>
  27. /// 获取一个新的id
  28. /// </summary>
  29. public static long LongId => GetInstance().GetLongId();
  30. /// <summary>
  31. /// 创建一个实例
  32. /// </summary>
  33. /// <returns></returns>
  34. public static SnowFlakeNew GetInstance()
  35. {
  36. return _snowFlake ??= new SnowFlakeNew();
  37. }
  38. /// <summary>
  39. /// 默认构造函数
  40. /// </summary>
  41. public SnowFlakeNew()
  42. {
  43. var bytes = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault().GetPhysicalAddress().GetAddressBytes();
  44. _workerId = bytes[4] << 2 | bytes[5];
  45. }
  46. /// <summary>
  47. /// 构造函数
  48. /// </summary>
  49. /// <param name="machineId">机器码</param>
  50. public SnowFlakeNew(int machineId)
  51. {
  52. if (machineId >= 0)
  53. {
  54. if (machineId > 1024)
  55. {
  56. throw new Exception("机器码ID非法");
  57. }
  58. _workerId = machineId;
  59. }
  60. }
  61. /// <summary>
  62. /// 设置起始偏移量
  63. /// </summary>
  64. /// <param name="offset"></param>
  65. public static void SetInitialOffset(long offset)
  66. {
  67. Offset = offset;
  68. }
  69. /// <summary>
  70. /// 设置数制格式化器
  71. /// </summary>
  72. /// <param name="nf"></param>
  73. public static void SetNumberFormater(NumberFormater nf)
  74. {
  75. _numberFormater = nf;
  76. }
  77. public long GetLongId()
  78. {
  79. lock (LockObj)
  80. {
  81. long timestamp = DateTime.Now.GetTotalMilliseconds();
  82. if (_lastTimestamp == timestamp)
  83. { //同一微妙中生成ID
  84. _sequence = (_sequence + 1) & SequenceMask; //用&运算计算该微秒内产生的计数是否已经到达上限
  85. if (_sequence == 0)
  86. {
  87. //一微妙内产生的ID计数已达上限,等待下一微妙
  88. timestamp = DateTime.Now.GetTotalMilliseconds();
  89. while (timestamp <= _lastTimestamp)
  90. {
  91. timestamp = DateTime.Now.GetTotalMilliseconds();
  92. }
  93. return timestamp;
  94. }
  95. }
  96. else
  97. { //不同微秒生成ID
  98. _sequence = 0; //计数清0
  99. }
  100. if (timestamp < _lastTimestamp)
  101. { //如果当前时间戳比上一次生成ID时时间戳还小,抛出异常,因为不能保证现在生成的ID之前没有生成过
  102. throw new Exception($"Clock moved backwards. Refusing to generate id for {_lastTimestamp - timestamp} milliseconds");
  103. }
  104. _lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
  105. return (_workerId << 52 | (timestamp - Twepoch << 12) | _sequence) - Offset;
  106. }
  107. }
  108. /// <summary>
  109. /// 获取一个字符串表示形式的id
  110. /// </summary>
  111. /// <returns></returns>
  112. public string GetUniqueId()
  113. {
  114. return _numberFormater.ToString(GetLongId());
  115. }
  116. /// <summary>
  117. /// 获取一个字符串表示形式的id
  118. /// </summary>
  119. /// <param name="maxLength">最大长度,至少6位</param>
  120. /// <returns></returns>
  121. public string GetUniqueShortId(int maxLength = 8)
  122. {
  123. if (maxLength < 6)
  124. {
  125. throw new ArgumentException("最大长度至少需要6位");
  126. }
  127. string id = GetUniqueId();
  128. int index = id.Length - maxLength;
  129. if (index < 0)
  130. {
  131. index = 0;
  132. }
  133. return id.Substring(index);
  134. }
  135. }