Python利用雪花算法实现生成唯一ID
作者:Sir?老王 发布时间:2022-10-18 14:49:06
雪花算法是在一个项目体系中生成全局唯一ID标识的一种方式,偶然间看到了Python使用雪花算法不尽感叹真的是太便捷了。
它生成的唯一ID的规则也是通过常用的时间戳来统计的,但是计算方式却更为精准。除此之外,再配合上不同机器属性分布式的使用就可以使生成的ID在整个单击或是分布式项目保持唯一性。
雪花算法通过时间规则,以二进制的方式将进行时间戳以及机器属性等信息的填充,所以生成后的唯一ID是按照时间递增的规律来排列的。为了形成对比,下面先看看在Java开发中的雪花算法是如何生成唯一ID的。
package utils;
public class Snowflake {
/** 开始时间截 (2015-01-01) */
private final long twepoch = 1420041600000L;
/** 机器id所占的位数 */
private final long workerIdBits = 5L;
/** 数据标识id所占的位数 */
private final long datacenterIdBits = 5L;
/** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
/** 支持的最大数据标识id,结果是31 */
private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
/** 序列在id中占的位数 */
private final long sequenceBits = 12L;
/** 机器ID向左移12位 */
private final long workerIdShift = sequenceBits;
/** 数据标识id向左移17位(12+5) */
private final long datacenterIdShift = sequenceBits + workerIdBits;
/** 时间截向左移22位(5+5+12) */
private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
/** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */
private final long sequenceMask = -1L ^ (-1L << sequenceBits);
/** 工作机器ID(0~31) */
private long workerId;
/** 数据中心ID(0~31) */
private long datacenterId;
/** 毫秒内序列(0~4095) */
private long sequence = 0L;
/** 上次生成ID的时间截 */
private long lastTimestamp = -1L;
public Snowflake(long workerId, long datacenterId) {
if (workerId > maxWorkerId || workerId < 0) {
throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
}
if (datacenterId > maxDatacenterId || datacenterId < 0) {
throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
}
this.workerId = workerId;
this.datacenterId = datacenterId;
}
public synchronized long nextId() {
long timestamp = timeGen();
//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
if (timestamp < lastTimestamp) {
throw new RuntimeException(
String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
}
//如果是同一时间生成的,则进行毫秒内序列
if (lastTimestamp == timestamp) {
sequence = (sequence + 1) & sequenceMask;
//毫秒内序列溢出
if (sequence == 0) {
//阻塞到下一个毫秒,获得新的时间戳
timestamp = tilNextMillis(lastTimestamp);
}
}
//时间戳改变,毫秒内序列重置
else {
sequence = 0L;
}
//上次生成ID的时间截
lastTimestamp = timestamp;
//移位并通过或运算拼到一起组成64位的ID
return ((timestamp - twepoch) << timestampLeftShift) //
| (datacenterId << datacenterIdShift) //
| (workerId << workerIdShift) //
| sequence;
}
protected long tilNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
protected long timeGen() {
return System.currentTimeMillis();
}
public static void main(String[] args) {
Snowflake idWorker = new Snowflake(0, 0);
for (int i = 0; i < 100; i++) {
long id = idWorker.nextId();
System.out.println(Long.toBinaryString(id));
System.out.println(id);
}
}
}
通过上述的Java代码块就能生成100个唯一的ID,并且在Java代码块中定义生成ID时各种属性信息,大概有100行代码左右,我截取了生成唯一ID的部分结果来展示。
111001000000000011001001011001011010110000000000000000010111
1026834554947633175
111001000000000011001001011001011010110000000000000000011000
1026834554947633176
111001000000000011001001011001011011000000000000000000000000
1026834554951827456
111001000000000011001001011001011011000000000000000000000001
1026834554951827457
这样的代码块可能使用C++的方式实现的话过程可能更为复杂,相比之下Python开发的话比较简单,因为大佬们已经将一些复杂的东西都写好了,我们经常只需要直接调用即可,这里说明一下不同编程语言都是我们做业务的一种工具,都有自己诞生的使命。
接下来,我们使用python调用第三方模块的方式来实现雪花算法,具体使用python实现雪花算法生成唯一ID的思路肯定和Java也是相似的。
在python中,大佬们已经封装了pysnowflake的python非标准库,这也是python之所以方便的原因,通过pip的方式将其安装完成就能大显身手了。
pip install pysnowflake -i https://pypi.tuna.tsinghua.edu.cn/simple/
安装完成之后需要启动雪花算法生成唯一ID的服务,并且可以定义工作的数量,这里我们将工作数量定义为1启动服务。
将snowflake.client导入到代码块中,相当于我们作为客户端去访问服务端就会直接生成唯一ID。
# Importing the `snowflake.client` module.
import snowflake.client
# Calling the `get_guid()` function from the `snowflake.client` module.
uuid = snowflake.client.get_guid()
# Printing the value of the `uuid` variable.
print(uuid)
# Printing the binary representation of the `uuid` variable.
print(bin(uuid))
# 4674877370191056897
# 0b100000011100000100000000011001100011010110000000001000000000001
来源:https://mp.weixin.qq.com/s/hVWs5xsbSF83I-SJmYIzHA


猜你喜欢
- 前言MySQL支持单机事务的良好表现毋庸置疑,那么在分布式系统中,涉及多个节点,MySQL又是如何实现分布式事务的呢?比如开发一个业务系统,
- 看了很多介绍javascript面向对象技术的文章,很晕.为什么?不是因为写得不好,而是因为太深奥.javascript中的对象还没解释清楚
- scrapy 框架结构思考scrapy 为什么是框架而不是库?scrapy是如何工作的?项目结构在开始爬取之前,必须创建一个新的Scrapy
- 线上有个需求,格式化,从一堆s1,s100-s199中找出连续的服并且格式化显示出来,如:神魔:S106-109,s123,s125御剑:
- 1. dataloader() 初始化函数def __init__(self, dataset, batch_size=1, shuffle
- 本文实例讲述了python读取word文档的方法。分享给大家供大家参考。具体如下:首先下载安装win32comfrom win32com i
- 一:模版的继承1.什么是模板继承?你需要事先在你想要使用的主页面上划定区域做好标记,之后在子页面继承的时候你就可以使用在主页面划定的区域,也
- asp在线备份sql server数据库: 1、备份sqlserver 代码如下:<% SQL="backup&n
- 整数的阶乘(英语:factorial)是所有小于及等于该数的正整数的积,0的阶乘为1。即:n!=1×2×3×...×n。首先导入math模块
- 工作中会遇到这样的需求,有多个Excel的格式一样,都有多个sheet,且每个sheet的名字和格式一样,我们需要按照sheet 合并,就是
- 1.安装模块Python 要使用 redis,需要先安装 redis 模块:pip install redis测试安装:redis 取出的结
- 一、安装pip2pi工具:pip install pip2pi或:git clone https://github.com/wolever/
- Python实战系列用于记录实战项目中的思路,代码实现,出现的问题与解决方案以及可行的改进方向本文为第2篇–200行Python代码实现20
- 数据结构&Series:'''series {索引 + 数据} 形式索引是自动生成的''
- 如果有人问你,GET和POST,有什么区别?你会如何回答?真实案例 前几天有人问我这个问题。
- python使用ctypes模块调用windows api GetVersionEx获取当前系统版本,没有使用python32#!c:/py
- 本文实例讲述了Python2与Python3的区别。分享给大家供大家参考,具体如下:python2与python3的区别1、性能2、编码格式
- http协议学习系列
- 导包import “github.com/smartystreets/goconvey”核心API顶
- 做查询页面,查询条件比较多的时候往往会涉及到级联。举个简单的例子,拿教务系统来说,我们要查询教学计划信息,查询条件是入学批次、学生层次(专升