关于 UUID 可以浏览 UUID。
最近听说一种新的 ID 生成器,叫做 NanoID,很多地方那个都把它拿来和 UUID 做对比。
根据查到的资料,好像最早是来自 JS 项目 NanoID。做比较的参考也是 NodeJS 版本的 UUID 实现。
这是两个 JS 库的 stars 数对比:NanoID ,UUID
。
相同之处:和 UUID4 差不多的随机位(UUID4 122,NanoID 126), 冲突概率差不多,而且都是 urlsafe 的。
更好的地方:
- 性能更好:资源占用少,计算速度快 (不一定适用于其他语言。但考虑到其设计的简单,性能更好应该比较正常)
- 采用更加大的字母表 => 更加紧凑
0-9
a-z
A-Z
_
-
64 个字符,相当于 urlsafe base64
相比之下,UUID 只采用0-9
a-f
十六个字符
所以最后,UUID 需要 36 个字符(包括四个横杠)来表示,NanoID 只需要 21 个字符。 - 采用更安全的硬件随机数生成器(NodeJS 版本采用
crypto
模块,浏览器环境采用 Web Crypto API,Python 版本采用os.urandom
) -
设计比 UUID 简单得多,代码量非常小,
我看了 Python 版本的实现,只是生成指定字母表的随机字符串,如果不需要自定义字母表,其实现可以缩短到以下几行代码:from os import urandom alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-' def nanoid(): id = '' while True: for random_byte in urandom(50): id += alphabet[random_byte & 63] if len(id) == 21: return id
PS: NanoID 的 Python 库真是有点过于累赘,明明一个很简单的逻辑,搞出好几个文件。
总结
UUID 的适用场景不会被这个简单的随机字符串替换,其复杂设计还是有它的价值在里面。
不过确实可以考虑采用更大的字母表来表示,将其缩短一些。
这个 NanoID 也没啥特别的,就是随机,这也算的话,我可以发表一种更简洁的算法:
from os import urandom
from base64 import urlsafe_b64encode
def angid():
return urlsafe_b64encode(urandom(15)).decode()
def angid2():
return urlsafe_b64encode(urandom(18)).decode()
andid 会生成 20 位长度的 ID,随机位 120,
angid2 会生成 24 位长度的 ID,随机位 144,
生成效率对比:
%timeit angid()
2.4 µs ± 34.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit angid2()
2.35 µs ± 20.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit nanoid() # 我上面的那个简化版本
6.75 µs ± 74.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit nanoid.generate()
10.1 µs ± 587 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit uuid.uuid1()
2.75 µs ± 171 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit uuid.uuid4()
3.57 µs ± 33.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
UUID 的生成速度确实令人震惊,比我想象中的要好得多。
PS: UUID 模块有部分采用 C 实现(_uuid
)。
PS: Python UUID4(基于随机)采用了硬件随机数生成器 os.urandom
。