如何通过雪花算法用Python实现一个简单的发号器


Posted in Python onJuly 03, 2019

实现一个简单的发号器

根据snowflake算法的原理实现一个简单的发号器,产生不重复、自增的id。

1.snowflake算法的简单描述

如何通过雪花算法用Python实现一个简单的发号器

这里的snowflake算法是用二进制的,有64位。其中41位的时间戳表示:当前时间戳减去某个设定的起始时间,10位标识表示:不同的机器、数据库的标识ID等等,序列号为每秒或每毫秒内自增的id。

我做的时候没有用位运算去实现,而是做了一个十进制的,16位的(当时项目要求是16位的)。但是实现发号器的基本策略是一样的,通过时间戳和标识来防止重复,通过序列号实现自增。当然啦,重点不是发号器多少位,而是根据项目的实际情况,利用snowflake算法的原理,实现一个适合自己项目的发号器。

2.Python实现

时间戳:9位,起始时间为2018-01-01 00:00:00 ,时间戳为当前时间减去起始时间。时间戳有9为,可用时间为 999999999/(606024*365)≈31(年)。

标识ID:2位,我用的时候比较简单,只是涉及一个数据库的情况,所以用一张数据表对应一个标识ID,可用100张表。

序列号:5位,我时间戳用的是秒级的,但是5位是10万个序列号,经过测试在一秒内是完全够用的。

所以时间戳、标识ID、序列号的位数也没规定说一定要多少,根据自己项目的实际来即可。

代码如下:

import time
class MySnow:
  def __init__(self,dataID):
    self.start = int(time.mktime(time.strptime('2018-01-01 00:00:00', "%Y-%m-%d %H:%M:%S")))
    self.last = int(time.time())
    self.countID = 0
    self.dataID = dataID  # 数据ID,这个自定义或是映射

  def get_id(self):
    # 时间差部分
    now = int(time.time())
    temp = now-self.start
    if len(str(temp)) < 9: # 时间差不够9位的在前面补0
      length = len(str(temp))
      s = "0" * (9-length)
      temp = s + str(temp)
    if now == self.last:
      self.countID += 1  # 同一时间差,序列号自增
    else:
      self.countID = 0  # 不同时间差,序列号重新置为0
      self.last = now
    # 标识ID部分
    if len(str(self.dataID)) < 2:
      length = len(str(self.dataID))
      s = "0" * (2-length)
      self.dataID = s + str(self.dataID)
    # 自增序列号部分
    if self.countID == 99999: # 序列号自增5位满了,睡眠一秒钟
      time.sleep(1)
    countIDdata = str(self.countID)
    if len(countIDdata) < 5: # 序列号不够5位的在前面补0
      length = len(countIDdata)
      s = "0"*(5-length)
      countIDdata = s + countIDdata
    id = str(temp) + str(self.dataID) + countIDdata
    return id

使用方法:

snow = MySnow(dataID="00")
print(snow.get_id())

其中dataID即为标识ID,countID为自增序列号。dataID可以一个通过自定义的映射表获得,这个视实际的项目情况而定。

3.关于并发

首先,直接用这个发号器是不能进行并发操作,会产生重复的id。如果真的要进行并发,那么就要权衡一下并发和位数的哪个更重要了!

拿实际例子来说吧,比如我并发的目的是为了节省时间,让程序更快的跑完,这时候为了并发,我把dataID中拿出一位来,标识不同的子进程,这样可以防止产生重复的id。但是实际上这用了位数去换取时间,如果是id位数比较少的情况,比如16位的,dataID比较少,我个人认为这样是不值得的,有些奢侈。这时候便是位数比并发重要啦。

当时如果位数充裕,比如20位的,需要并发就并发啦。

还有一种实现并发的方法,就是给发号器加锁,发号的时候加锁,发完了解锁。这个我没有试过,有兴趣的可以试一下哈哈。但是我有个疑惑啊,就是不断加锁和解锁切换,带来的时间和资源开销会不会很大呢。

Python 相关文章推荐
Python绑定方法与非绑定方法详解
Aug 18 Python
python pandas库中DataFrame对行和列的操作实例讲解
Jun 09 Python
详解python 3.6 安装json 模块(simplejson)
Apr 02 Python
详解Python3序列赋值、序列解包
May 14 Python
PyTorch之图像和Tensor填充的实例
Aug 18 Python
python 利用已有Ner模型进行数据清洗合并代码
Dec 24 Python
Django Admin设置应用程序及模型顺序方法详解
Apr 01 Python
python rolling regression. 使用 Python 实现滚动回归操作
Jun 08 Python
python 解决selenium 中的 .clear()方法失效问题
Sep 01 Python
Python爬虫进阶之爬取某视频并下载的实现
Dec 08 Python
python中pyqtgraph知识点总结
Jan 26 Python
利用For循环遍历Python字典的三种方法实例
Mar 25 Python
Python实现个人微信号自动监控告警的示例
Jul 03 #Python
python pandas模块基础学习详解
Jul 03 #Python
python将excel转换为csv的代码方法总结
Jul 03 #Python
pandas实现to_sql将DataFrame保存到数据库中
Jul 03 #Python
python实现控制COM口的示例
Jul 03 #Python
python pandas时序处理相关功能详解
Jul 03 #Python
在linux下实现 python 监控usb设备信号
Jul 03 #Python
You might like
php xml 入门学习资料
2011/01/01 PHP
PHP 使用pcntl和libevent 实现Timer功能
2013/10/27 PHP
盘点PHP和ASP.NET的10大对比!
2015/12/24 PHP
php检查函数必传参数是否存在的实例详解
2017/08/28 PHP
Laravel框架分页实现方法分析
2018/06/12 PHP
另类调用flash无须激活的方法
2006/12/27 Javascript
javascript下string.format函数补充
2010/08/24 Javascript
jquery bind(click)传参让列表中每行绑定一个事件
2014/08/06 Javascript
JS+CSS实现简单的二级下拉导航菜单效果
2015/09/21 Javascript
超精准的javascript验证身份证号的具体实现方法
2015/11/18 Javascript
完美解决IE9浏览器出现的对象未定义问题
2016/09/29 Javascript
为jQuery-easyui的tab组件添加右键菜单功能的简单实例
2016/10/10 Javascript
详解Js中的模块化是如何实现的
2017/10/18 Javascript
vue3.0 CLI - 2.2 - 组件 home.vue 的初步改造
2018/09/14 Javascript
解决Idea、WebStorm下使用Vue cli脚手架项目无法使用Webpack别名的问题
2019/10/11 Javascript
微信小程序12行js代码自己写个滑块功能(推荐)
2020/07/15 Javascript
vue 避免变量赋值后双向绑定的操作
2020/11/07 Javascript
JavaScript 防抖和节流遇见的奇怪问题及解决
2020/11/20 Javascript
python中threading超线程用法实例分析
2015/05/16 Python
Python使用defaultdict读取文件各列的方法
2017/05/11 Python
对numpy中的数组条件筛选功能详解
2018/07/02 Python
python之验证码生成(gvcode与captcha)
2019/01/02 Python
Python实现手机号自动判断男女性别(实例解析)
2019/12/22 Python
Python接口测试结果集实现封装比较
2020/05/01 Python
详解Python多线程下的list
2020/07/03 Python
详解H5 活动页之移动端 REM 布局适配方法
2017/12/07 HTML / CSS
法国大使拉杆箱官网:DELSEY Paris
2018/03/20 全球购物
函授毕业生自我鉴定范文
2014/03/25 职场文书
教师四风自我剖析材料
2014/09/30 职场文书
小学教师师德培训心得体会
2016/01/09 职场文书
Python趣味挑战之实现简易版音乐播放器
2021/05/28 Python
Java实现简易的分词器功能
2021/06/15 Java/Android
python not运算符的实例用法
2021/06/30 Python
Win11任务栏太宽了怎么办?一招解决Win11任务栏太宽问题
2021/11/21 数码科技
SpringCloud Function SpEL注入漏洞分析及环境搭建
2022/04/08 Java/Android
MySQL深分页问题解决思路
2022/12/24 MySQL