如何通过雪花算法用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实现哈希表
Feb 07 Python
详解Python使用simplejson模块解析JSON的方法
Mar 24 Python
python3模块smtplib实现发送邮件功能
May 22 Python
对python多线程与global变量详解
Nov 09 Python
Python基于Opencv来快速实现人脸识别过程详解(完整版)
Jul 11 Python
python通过SSH登陆linux并操作的实现
Oct 10 Python
pytorch实现建立自己的数据集(以mnist为例)
Jan 18 Python
Python实现代码块儿折叠
Apr 15 Python
Python中的__init__作用是什么
Jun 09 Python
解决python 执行shell命令无法获取返回值的问题
Dec 05 Python
Python 调用C++封装的进一步探索交流
Mar 04 Python
python图片灰度化处理的几种方法
Jun 23 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验证码类代码( 最新修改,完全定制化! )
2010/12/02 PHP
thinkPHP5.0框架应用请求生命周期分析
2017/03/25 PHP
PHP设计模式之单例模式定义与用法分析
2019/03/26 PHP
PHP队列场景以及实现代码实例详解
2021/02/26 PHP
通过jquery实现tab标签浏览效果
2007/02/20 Javascript
地址栏上的一段语句,改变页面的风格。(教程)
2008/04/02 Javascript
jQuery入门知识简介
2010/03/04 Javascript
jquery中对于批量deferred的处理方法
2014/01/22 Javascript
jQuery 隐藏和显示 input 默认值示例
2014/06/03 Javascript
加随机数引入脚本不让浏览器读取缓存
2014/09/04 Javascript
js实现prototype扩展的方法(字符串,日期,数组扩展)
2016/01/14 Javascript
JS模拟简易滚动条效果代码(附demo源码)
2016/04/05 Javascript
JS控制TreeView的结点选择
2016/11/11 Javascript
微信小程序教程系列之设置标题栏和导航栏(7)
2020/06/29 Javascript
bootstrap日期控件问题(双日期、清空等问题解决)
2017/04/19 Javascript
Angular2学习教程之TemplateRef和ViewContainerRef详解
2017/05/25 Javascript
解决vue-cli中stylus无法使用的问题方法
2017/06/19 Javascript
详解使用vue实现tab 切换操作
2017/07/03 Javascript
js canvas实现星空连线背景特效
2019/11/01 Javascript
在vue中阻止浏览器后退的实例
2019/11/06 Javascript
如何实现iframe父子传参通信
2020/02/05 Javascript
javascript实现计算器功能
2020/03/30 Javascript
[42:36]DOTA2上海特级锦标赛B组败者赛 VG VS Spirit第二局
2016/02/26 DOTA
[36:09]Secret vs VG 2019国际邀请赛淘汰赛 败者组 BO3 第一场 8.24
2019/09/10 DOTA
跟老齐学Python之不要红头文件(1)
2014/09/28 Python
python中异常捕获方法详解
2017/03/03 Python
Tornado 多进程实现分析详解
2018/01/12 Python
Python configparser模块操作代码实例
2020/06/08 Python
利用python清除移动硬盘中的临时文件
2020/10/28 Python
前端H5 Video常见使用场景简介
2020/08/21 HTML / CSS
路政管理毕业自荐书范文
2014/02/10 职场文书
中国梦主题教育活动总结
2014/05/05 职场文书
房地产开发项目建议书
2014/05/16 职场文书
社保转移委托书范本
2014/10/08 职场文书
庆祝国庆节标语
2014/10/09 职场文书
男方家长婚礼致辞
2015/07/27 职场文书