109 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			109 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
| # Twitter's Snowflake algorithm implementation which is used to generate distributed IDs.
 | ||
| # https://github.com/twitter-archive/snowflake/blob/snowflake-2010/src/main/scala/com/twitter/service/snowflake/IdWorker.scala
 | ||
| 
 | ||
| from random import randint
 | ||
| import time
 | ||
| from server.settings import SNOW_DATACENTER_ID
 | ||
| 
 | ||
| 
 | ||
| class InvalidSystemClock(Exception):
 | ||
|     """
 | ||
|     时钟回拨异常
 | ||
|     """
 | ||
|     pass
 | ||
| 
 | ||
| 
 | ||
| class Constant(object):
 | ||
|     # 64位ID的划分
 | ||
|     WORKER_ID_BITS = 6
 | ||
|     DATACENTER_ID_BITS = 5
 | ||
|     SEQUENCE_BITS = 12
 | ||
| 
 | ||
|     # 最大取值计算
 | ||
|     MAX_WORKER_ID = -1 ^ (-1 << WORKER_ID_BITS)  # 2**5-1 0b11111
 | ||
|     MAX_DATACENTER_ID = -1 ^ (-1 << DATACENTER_ID_BITS)
 | ||
| 
 | ||
|     # 移位偏移计算
 | ||
|     WOKER_ID_SHIFT = SEQUENCE_BITS
 | ||
|     DATACENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS
 | ||
|     TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATACENTER_ID_BITS
 | ||
| 
 | ||
|     # 序号循环掩码
 | ||
|     SEQUENCE_MASK = -1 ^ (-1 << SEQUENCE_BITS)
 | ||
| 
 | ||
|     # Twitter元年时间戳
 | ||
|     TWEPOCH = 1288834974657
 | ||
| 
 | ||
| 
 | ||
| class IdWorker(object):
 | ||
|     """
 | ||
|     用于生成IDs
 | ||
|     """
 | ||
| 
 | ||
|     def __init__(self, datacenter_id, worker_id, sequence=0):
 | ||
|         """
 | ||
|         初始化
 | ||
|         :param datacenter_id: 数据中心(机器区域)ID
 | ||
|         :param worker_id: 机器ID
 | ||
|         :param sequence: 起始序号
 | ||
|         """
 | ||
|         # sanity check
 | ||
|         if worker_id > Constant.MAX_WORKER_ID or worker_id < 0:
 | ||
|             raise ValueError('worker_id值越界')
 | ||
| 
 | ||
|         if datacenter_id > Constant.MAX_DATACENTER_ID or datacenter_id < 0:
 | ||
|             raise ValueError('datacenter_id值越界')
 | ||
| 
 | ||
|         self.worker_id = worker_id
 | ||
|         self.datacenter_id = datacenter_id
 | ||
|         self.sequence = sequence
 | ||
| 
 | ||
|         self.last_timestamp = -1  # 上次计算的时间戳
 | ||
| 
 | ||
|     def _gen_timestamp(self):
 | ||
|         """
 | ||
|         生成整数时间戳
 | ||
|         :return:int timestamp
 | ||
|         """
 | ||
|         return int(time.time() * 1000)
 | ||
| 
 | ||
|     def get_id(self):
 | ||
|         """
 | ||
|         获取新ID
 | ||
|         :return:
 | ||
|         """
 | ||
|         timestamp = self._gen_timestamp()
 | ||
| 
 | ||
|         # 时钟回拨
 | ||
|         if timestamp < self.last_timestamp:
 | ||
|             raise InvalidSystemClock
 | ||
| 
 | ||
|         if timestamp == self.last_timestamp:
 | ||
|             self.sequence = (self.sequence + 1) & Constant.SEQUENCE_MASK
 | ||
|             if self.sequence == 0:
 | ||
|                 timestamp = self._til_next_millis(self.last_timestamp)
 | ||
|         else:
 | ||
|             self.sequence = 0
 | ||
| 
 | ||
|         self.last_timestamp = timestamp
 | ||
| 
 | ||
|         new_id = ((timestamp - Constant.TWEPOCH) << Constant.TIMESTAMP_LEFT_SHIFT
 | ||
|                   ) | (self.datacenter_id << Constant.DATACENTER_ID_SHIFT) | \
 | ||
|             (self.worker_id << Constant.WOKER_ID_SHIFT) | self.sequence
 | ||
|         return new_id
 | ||
| 
 | ||
|     def _til_next_millis(self, last_timestamp):
 | ||
|         """
 | ||
|         等到下一毫秒
 | ||
|         """
 | ||
|         timestamp = self._gen_timestamp()
 | ||
|         while timestamp <= last_timestamp:
 | ||
|             timestamp = self._gen_timestamp()
 | ||
|         return timestamp
 | ||
| 
 | ||
| 
 | ||
| idWorker = IdWorker(SNOW_DATACENTER_ID, randint(1, 60))
 | ||
| 
 | ||
| if __name__ == '__main__':
 | ||
|     print(idWorker.get_id())
 |