3666.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. """
  2. @FileName:3666.py
  3. @Description:PyCharm
  4. @Author:Jerry Pan
  5. @Time:2023/5/3 17:50
  6. @Department:技术部
  7. @Copyright:©2019-2023
  8. """
  9. import time
  10. import logging
  11. import re
  12. class InputError(Exception):
  13. """Exception raised for errors in the input.
  14. Attributes:
  15. expression -- input expression in which the error occurred
  16. message -- explanation of the error
  17. """
  18. def __init__(self, expression, message):
  19. self.expression = expression
  20. self.message = message
  21. class InvalidUserAgentError(Exception):
  22. def __init__(
  23. self,
  24. message=None,
  25. ):
  26. self.message = message
  27. class InvalidSystemClock(Exception):
  28. def __init__(
  29. self,
  30. message=None,
  31. ):
  32. self.message = message
  33. class IdWorker(object):
  34. def __init__(self, worker_id, data_center_id):
  35. self.worker_id = worker_id
  36. self.data_center_id = data_center_id
  37. self.user_agent_parser = re.compile("[a-zA-Z][a-zA-Z\-0-9]*")
  38. self.logger = logging.getLogger("idworker")
  39. # stats
  40. self.ids_generated = 0
  41. self.twepoch = 1483200000000
  42. self.sequence = 0
  43. self.worker_id_bits = 5
  44. self.data_center_id_bits = 5
  45. self.max_worker_id = -1 ^ (-1 << self.worker_id_bits)
  46. self.max_data_center_id = -1 ^ (-1 << self.data_center_id_bits)
  47. self.sequence_bits = 12
  48. self.worker_id_shift = self.sequence_bits
  49. self.data_center_id_shift = self.sequence_bits + self.worker_id_bits
  50. self.timestamp_left_shift = (
  51. self.sequence_bits + self.worker_id_bits + self.data_center_id_bits
  52. )
  53. self.sequence_mask = -1 ^ (-1 << self.sequence_bits)
  54. self.last_timestamp = -1
  55. # Sanity check for worker_id
  56. if self.worker_id > self.max_worker_id or self.worker_id < 0:
  57. raise InputError(
  58. "worker_id",
  59. "worker id can't be greater than %i or less than 0"
  60. % self.max_worker_id,
  61. )
  62. if self.data_center_id > self.max_data_center_id or self.data_center_id < 0:
  63. raise InputError(
  64. "data_center_id",
  65. "data center id can't be greater than %i or less than 0"
  66. % self.max_data_center_id,
  67. )
  68. self.logger.info(
  69. "worker starting. timestamp left shift %d, data center id bits %d, worker id bits %d, sequence bits %d, worker id %d"
  70. % (
  71. self.timestamp_left_shift,
  72. self.data_center_id_bits,
  73. self.worker_id_bits,
  74. self.sequence_bits,
  75. self.worker_id,
  76. )
  77. )
  78. def _time_gen(self):
  79. return int(time.time() * 1000)
  80. def _till_next_millis(self, last_timestamp):
  81. timestamp = self._time_gen()
  82. while timestamp <= last_timestamp:
  83. timestamp = self._time_gen()
  84. return timestamp
  85. def _next_id(self):
  86. timestamp = self._time_gen()
  87. if self.last_timestamp > timestamp:
  88. self.logger.warning(
  89. "clock is moving backwards. Rejecting request until %i"
  90. % self.last_timestamp
  91. )
  92. raise InvalidSystemClock(
  93. "Clock moved backwards. Refusing to generate id for %i milliseocnds"
  94. % self.last_timestamp
  95. )
  96. if self.last_timestamp == timestamp:
  97. self.sequence = (self.sequence + 1) & self.sequence_mask
  98. if self.sequence == 0:
  99. timestamp = self._till_next_millis(self.last_timestamp)
  100. else:
  101. self.sequence = 0
  102. self.last_timestamp = timestamp
  103. new_id = (
  104. ((timestamp - self.twepoch) << self.timestamp_left_shift)
  105. | (self.data_center_id << self.data_center_id_shift)
  106. | (self.worker_id << self.worker_id_shift)
  107. | self.sequence
  108. )
  109. self.ids_generated += 1
  110. return new_id
  111. def _valid_user_agent(self, user_agent):
  112. return self.user_agent_parser.search(user_agent) is not None
  113. def get_worker_id(self):
  114. return self.worker_id
  115. def get_timestamp(self):
  116. return self._time_gen()
  117. def get_id(self):
  118. new_id = self._next_id()
  119. self.logger.debug(
  120. "id: %i worker_id: %i data_center_id: %i"
  121. % (new_id, self.worker_id, self.data_center_id)
  122. )
  123. return new_id
  124. def get_datacenter_id(self):
  125. return self.data_center_id
  126. if __name__ == "__main__":
  127. a = time.time()
  128. id_worker = IdWorker(2, 3)
  129. new_id = id_worker.get_id()
  130. print(new_id)
  131. s = set()
  132. for _ in range(1000000):
  133. s.add(id_worker.get_id())
  134. print(len(s))
  135. print(time.time() - a)
  136. # import uuid
  137. #
  138. # a = time.time()
  139. # s = set()
  140. # print(uuid.uuid4().hex)
  141. # for _ in range(1000000):
  142. # s.add(uuid.uuid4().hex)
  143. # print(len(s))
  144. # print(time.time() - a)