Last active
June 23, 2023 14:08
-
-
Save strizhechenko/7462de340756043455da8fb12f4d619d to your computer and use it in GitHub Desktop.
Компактные человекочитаемые уникальные идентификаторы для небольших несинхронизирующихся распределённых систем.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from base64 import b64encode | |
from time import time | |
import os | |
pid = os.getpid() | |
if pid == 1: # для поддержки запуска в контейнерах | |
import socket | |
hostname = socket.gethostname() | |
pid = ord(hostname[0]) + ord(hostname[-1]) | |
def uuid05(machines=10, ttl=2 * 86400, precision=0) -> int: | |
""" | |
Компактные человекочитаемые уникальные идентификаторы для временных объектов | |
в небольших несинхронизирующихся распределённых системах. Если объекты живут вечно - вам к nanoid. | |
Если нужно разом сгенерировать несколько uid - сгенерируйте один и приклейте порядковый номер объекта к нему. | |
%timeit uuid05() - 2.1 µs ± 2.08 ns per loop @ 3.2GHz | |
:arg machines - число машин в системе; | |
:arg ttl - через сколько секунд объект с uid, который может вернуть фукнция, гарантированно исчезает из системы; | |
:arg precision (optional) - переопределение точности, если объекты создаются часто. Максимум - 6. | |
>>> assert uuid05(2, 3600) <= 132400 | |
>>> assert uuid05(10, 3600) <= 932400 | |
>>> assert uuid05(10, 3600, 2) <= 9356400 | |
>>> assert uuid05(10, 2 * 86400) <= 91555200 | |
>>> assert uuid05(16, 3600) <= 15356400 | |
>>> assert uuid05(16, 1800) <= 15178200 | |
""" | |
precision = min(6, precision or int(machines ** (1 / 4))) | |
run_id = pid % (machines - 1) | |
time_id = int((time() % ttl) * 10 ** precision) | |
return int(f'{run_id}{time_id}') | |
def _uuid05_maxval(machines=10, ttl=2 * 24 * 60 * 60, precision=None) -> int: | |
""" | |
Функция, вычисляющая максимальное значение uuid05 при заданных параметрах. | |
:arg machines - число машин в системе; | |
:arg ttl - секунды, спустя которые объект с uid, который может вернуть фукнция, гарантированно исчезнет из системы; | |
:arg precision (optional) - можно переопределить точность, если объекты создаются очень часто. Не больше 6. | |
""" | |
precision = min(precision or int(machines ** (1 / 4)), 6) | |
run_id = machines - 1 | |
time_id = ttl * ((10 ** precision) - 1) | |
return int(f'{run_id}{time_id}') | |
def int2b64(uid: int, *args, **kwargs) -> str: | |
""" | |
Если вы используете uuid05 как строку, хочется ещё компактнее, а число не имеет значения - эта функция для вас. | |
Под капотом используется b64encode, которому можно прозрачно прокинуть аргументы. | |
Так-как декодирование не подразумевается, невозбранно избавляемся от паддинга. | |
%timeit b64(uuid05()) - 2.87 µs ± 13.9 ns per loop @ 3.2GHz | |
>>> int2b64(3136979908, altchars=b'_-') | |
'uvqDxA' | |
>>> int2b64(29136919548, altchars=b'_-') | |
'BsiyG-w' | |
""" | |
uid_as_bytes = uid.to_bytes((uid.bit_length() + 7) // 8, byteorder='big') | |
return b64encode(uid_as_bytes, *args, **kwargs).decode().replace('=', '') | |
if __name__ == '__main__': | |
print(_uuid05_maxval(2, 3600)) | |
print(_uuid05_maxval(10, 3600)) | |
print(_uuid05_maxval(10, 3600, 2)) | |
print(_uuid05_maxval(16, 3600)) | |
print(_uuid05_maxval(16, 1800)) | |
u = uuid05(100, 2 * 24 * 60 * 60) | |
print(u, int2b64(u, altchars=b'_-')) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment