SnowFlakeNew.cs 4.3 KB

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