SnowFlake.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. using Masuit.Tools.DateTimeExt;
  2. using Masuit.Tools.Strings;
  3. using System;
  4. using System.Linq;
  5. using System.Net.NetworkInformation;
  6. namespace Masuit.Tools.Systems
  7. {
  8. /// <summary>
  9. /// 动态生产有规律的分布式ID
  10. /// </summary>
  11. public class SnowFlake
  12. {
  13. #region 私有字段
  14. private static long Offset = 0L; //起始偏移量
  15. private static long _machineId; //机器码
  16. private static long _sequence; //计数从零开始
  17. private static long _lastTimestamp = -1L; //最后时间戳
  18. private const long Twepoch = 687888001020L; //唯一时间随机量
  19. private const int MachineBits = 10; //机器码字节数
  20. private const int SequenceBits = 12; //计数器字节数,12个字节用来保存计数码
  21. private const int MachineLeft = SequenceBits; //机器码数据左移位数,就是后面计数器占用的位数
  22. private const long TimestampLeft = MachineBits + SequenceBits; //时间戳左移动位数就是机器码+计数器总字节数+数据字节数
  23. private const long SequenceMask = -1L ^ -1L << SequenceBits; //一毫秒内可以产生计数,如果达到该值则等到下一毫秒在进行生成
  24. private static readonly object SyncRoot = new object(); //加锁对象
  25. private static NumberFormater _numberFormater = new NumberFormater(36);
  26. private static SnowFlake _snowFlake;
  27. #endregion 私有字段
  28. /// <summary>
  29. /// 获取一个新的id
  30. /// </summary>
  31. public static string NewId => GetInstance().GetUniqueId();
  32. /// <summary>
  33. /// 获取一个新的id
  34. /// </summary>
  35. public static long LongId => GetInstance().GetLongId();
  36. /// <summary>
  37. /// 创建一个实例
  38. /// </summary>
  39. /// <returns></returns>
  40. public static SnowFlake GetInstance()
  41. {
  42. return _snowFlake ??= new SnowFlake();
  43. }
  44. /// <summary>
  45. /// 默认构造函数
  46. /// </summary>
  47. public SnowFlake()
  48. {
  49. var bytes = NetworkInterface.GetAllNetworkInterfaces().FirstOrDefault().GetPhysicalAddress().GetAddressBytes();
  50. Snowflakes(bytes[4] << 2 | bytes[5]);
  51. }
  52. /// <summary>
  53. /// 构造函数
  54. /// </summary>
  55. /// <param name="machineId">机器码</param>
  56. public SnowFlake(long machineId)
  57. {
  58. Snowflakes(machineId);
  59. }
  60. private void Snowflakes(long machineId)
  61. {
  62. if (machineId >= 0)
  63. {
  64. if (machineId > 1024)
  65. {
  66. throw new Exception("机器码ID非法");
  67. }
  68. _machineId = machineId;
  69. }
  70. }
  71. /// <summary>
  72. /// 设置数制格式化器
  73. /// </summary>
  74. /// <param name="nf"></param>
  75. public static void SetNumberFormater(NumberFormater nf)
  76. {
  77. _numberFormater = nf;
  78. }
  79. /// <summary>
  80. /// 设置起始偏移量
  81. /// </summary>
  82. /// <param name="offset"></param>
  83. public static void SetInitialOffset(long offset)
  84. {
  85. Offset = offset;
  86. }
  87. /// <summary>
  88. /// 获取长整形的ID
  89. /// </summary>
  90. /// <returns></returns>
  91. public long GetLongId()
  92. {
  93. lock (SyncRoot)
  94. {
  95. var timestamp = DateTime.UtcNow.GetTotalMilliseconds();
  96. if (_lastTimestamp == timestamp)
  97. {
  98. //同一毫秒中生成ID
  99. _sequence = (_sequence + 1) & SequenceMask; //用&运算计算该毫秒内产生的计数是否已经到达上限
  100. if (_sequence == 0)
  101. {
  102. //一毫秒内产生的ID计数已达上限,等待下一毫秒
  103. timestamp = DateTime.UtcNow.GetTotalMilliseconds();
  104. }
  105. }
  106. else
  107. {
  108. //不同毫秒生成ID
  109. _sequence = 0L;
  110. }
  111. _lastTimestamp = timestamp; //把当前时间戳保存为最后生成ID的时间戳
  112. long id = ((timestamp - Twepoch) << (int)TimestampLeft) | (_machineId << MachineLeft) | _sequence;
  113. return id - Offset;
  114. }
  115. }
  116. /// <summary>
  117. /// 获取一个字符串表示形式的id
  118. /// </summary>
  119. /// <returns></returns>
  120. public string GetUniqueId()
  121. {
  122. return _numberFormater.ToString(GetLongId());
  123. }
  124. /// <summary>
  125. /// 获取一个字符串表示形式的id
  126. /// </summary>
  127. /// <param name="maxLength">最大长度,至少6位</param>
  128. /// <returns></returns>
  129. public string GetUniqueShortId(int maxLength = 8)
  130. {
  131. if (maxLength < 6)
  132. {
  133. throw new ArgumentException("最大长度至少需要6位");
  134. }
  135. string id = GetUniqueId();
  136. int index = id.Length - maxLength;
  137. if (index < 0)
  138. {
  139. index = 0;
  140. }
  141. return id.Substring(index);
  142. }
  143. }
  144. }