不败君

前端萌新&初级后端攻城狮

Python生成十万个无序且唯一的数字

Python生成十万个无序且唯一的数字

2020-04-30 18:05:00

围观(2887)

数字无处不在, 在一些应用场景就特别需要, 比如 订单号 / 防伪码 / 抽奖 / 用户编号 等.


订单号一般都是即时生成的, 比如很多都是用下单时间或者时间戳 如:2020043018010005 或者 1588240860000 还能再加上用户 ID 和随机数, 所以就没什么难度.


但是有些应用场景就不一样了, 比如防伪码和用户编号, 防伪码可能有十万个或者更多, 就需要一次性批量的生成了, 并且还要保证唯一性, 另外因为防伪码的特殊性还需要保证无序. 如果用户编号想做到无序也是一样, 需要先批量生成存储到某个容器, 然后依次拿出使用.


查阅了一些资料, 想了解一下怎么样才能又快又能保证唯一性和无序的大量生成数字, 看到了 "雪花算法", 但是感觉有点难. 劝退了...


博主有简单学一下 Python , 所以就拿 Python 写一下(献丑了)

import random

lst_number = []
lst_selected_number = []

start_number = 1000000      # 开始数字
end_number = 9999999        # 结束数字
num = 100000                # 生成数量

if end_number <= start_number:
    print('结束数字不能小于开始数字')
    exit()

for x in range(start_number, end_number):
    lst_number.append(x)

lst_selected_number = random.sample(lst_number, num)
print(lst_selected_number)

将上面代码复制保存到 number.py 并运行. 会打印出一个装满了十万个数字的列表:

1.png

这样一下子就生成出来了十万个无序且唯一的数字.

逻辑很简单, 就是先设置一个空列表, 然后循环遍历开始数字到结束数字, 比如从 1000000 开始, 到 9999999 结束, 将每个遍历出来的数字装入列表, 那么这个列表的元素就有 1000001, 1000002 1000003 ... 直到 9999998. 遍历完成后列表就一共有九百万个数字, 使用 random.sample 函数就能直接从列表的九百万个数字中抽取十万个数字出来, 且是不重复的抽. 所以就拿到了十万个唯一且无序的数字.


拿到数字之后可以保存到一些容器按需使用, 但是仔细看上图, 每个数字的长度都是七位. 假如防伪码需要的是十一位呢, 可以修改代码的开始数字为 10000000000 到 99999999999 然后运行代码会发现, 没反应了... 再打开系统任务管理器, 发现 Python 占用的内存极高.

2.png


再过没多久, 就直接报错了.

3.png

内存不够了...

盲猜是因为遍历存入列表, 列表数据太多把内存撑爆了, 所以使用 Redis 的列表进行存储:

import random
import redis

pool = redis.ConnectionPool(host = 'localhost', port = 6379, decode_responses = true)
container_box = redis.Redis(connection_pool = pool) # 连接池

start_number = 10000000000      # 开始数字
end_number = 99999999999        # 结束数字

if end_number <= start_number:
    print('结束数字不能小于开始数字')
    exit()

for x in range(start_number, end_number):
    container_box.lpush("list1", x)

print(container_box.llen("list1"))

执行代码, Redis 会开始存储数字, 使用可视化工具看得很直观

4.png


但是问题来了, 按照之前代码(本文第一段代码)生成九百万个数字的效率, 时间应该是两秒, 第二段代码生成十一位的数字就是九百亿个, 假设一秒能完成九百万个数字, 那也要 10000 秒, 就是最快也要 3 个小时... 但实际肯定是不止的.

博主用了大概两个半小时才生成了七千万个数字就放弃了...


如果已经完成数字遍历并将数字存入了 Redis, 接下来要做的就是按需使用, 需要使用数字的时候, 从 0 到 90000000000 (九百亿) 取一个随机数字, 拿列表中这个随机数字(Key)的元素, 拿取之后记得删除该元素.


经过博主的测试, 生成十万个长度八位(10000000 - 99999999 之间)的数字(无序且唯一)需要用时 17 秒(不使用 Redis)左右.

5.png

九位及以上就爆内存了.. 运行代码的机器是 16G 的. 如果电脑有 32G 或许可以挑战一下11位.

本文地址 : bubaijun.com/page.php?id=177

版权声明 : 未经允许禁止转载!

评论:我要评论
发布评论:
Copyright © 不败君 粤ICP备18102917号-1

不败君

首 页 作 品 微 语