如何通过雪花算法用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 相关文章推荐
忘记ftp密码使用python ftplib库暴力破解密码的方法示例
Jan 22 Python
在Django中限制已登录用户的访问的方法
Jul 23 Python
详解python单例模式与metaclass
Jan 15 Python
简单谈谈Python中的几种常见的数据类型
Feb 10 Python
Django使用Celery异步任务队列的使用
Mar 13 Python
python给微信好友定时推送消息的示例
Feb 20 Python
浅谈python3.6的tkinter运行问题
Feb 22 Python
基于python 微信小程序之获取已存在模板消息列表
Aug 05 Python
Python facenet进行人脸识别测试过程解析
Aug 16 Python
Python3 A*寻路算法实现方式
Dec 24 Python
Python发起请求提示UnicodeEncodeError错误代码解决方法
Apr 21 Python
python3判断IP地址的方法
Mar 04 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
神族 Protoss 剧情介绍
2020/03/14 星际争霸
第六节 访问属性和方法 [6]
2006/10/09 PHP
基于initPHP的框架介绍
2013/04/18 PHP
php禁止某ip或ip地址段访问的方法
2015/02/25 PHP
功能强大的PHP图片处理类(水印、透明度、旋转)
2015/10/21 PHP
PHP实现的线索二叉树及二叉树遍历方法详解
2016/04/25 PHP
PHP获取用户访问IP地址的5种方法
2016/05/16 PHP
Laravel 修改默认日志文件名称和位置的例子
2019/10/17 PHP
PHP设计模式之命令模式示例详解
2020/12/20 PHP
JavaScript 常用函数库详解
2009/10/21 Javascript
分享14个很酷的jQuery导航菜单插件
2011/04/25 Javascript
Jquery实现列表(隔行换色,全选,鼠标滑过当前行)效果实例
2013/06/09 Javascript
jquery实现点击消失的代码
2014/03/03 Javascript
javascript获取网页宽高方法汇总
2015/07/19 Javascript
js中常用的Tab切换效果(推荐)
2016/08/30 Javascript
关于jQuery里prev()的简单操作代码
2017/10/27 jQuery
使用vue-cli+webpack搭建vue开发环境的方法
2017/12/22 Javascript
Angular+ionic实现折叠展开效果的示例代码
2020/07/29 Javascript
vue 使用原生组件上传图片的实例
2020/09/08 Javascript
[41:11]完美世界DOTA2联赛PWL S2 Inki vs Magma 第一场 11.22
2020/11/24 DOTA
Python程序中使用SQLAlchemy时出现乱码的解决方案
2015/04/24 Python
举例简单讲解Python中的数据存储模块shelve的用法
2016/03/03 Python
Python对字符串实现去重操作的方法示例
2017/08/11 Python
基于python全局设置id 自动化测试元素定位过程解析
2019/09/04 Python
Python3+Requests+Excel完整接口自动化测试框架的实现
2019/10/11 Python
Python代码生成视频的缩略图的实例讲解
2019/12/22 Python
html5使用canvas画空心圆与实心圆
2014/12/15 HTML / CSS
幼儿园六一儿童节文艺汇演主持词
2014/03/21 职场文书
项目经理任命书
2014/06/04 职场文书
2014年党课学习心得体会
2014/07/08 职场文书
第28个世界无烟日活动总结
2015/02/10 职场文书
杨善洲电影观后感
2015/06/04 职场文书
遗失证明范文
2015/06/19 职场文书
关于做家务的心得体会
2016/01/23 职场文书
pytorch常用数据类型所占字节数对照表一览
2021/05/17 Python
Win11显卡控制面板打开显卡设置方法
2022/04/20 数码科技