【问题标题】:How to generate 8 bytes unique random number in python?如何在 python 中生成 8 个字节的唯一随机数?
【发布时间】:2020-10-28 23:52:49
【问题描述】:

有没有什么方法可以在 python 语言中生成一个 8 字节 大小的唯一随机数?我使用了 UUID 库,但它有 16 个字节,这与我的要求不一致。

任何帮助将不胜感激。

提前致谢

【问题讨论】:

  • unique 到底是什么意思?你会用这个数字做什么,大小限制来自哪里?
  • 所以,有前端和后端部分。在后端,我使用 UUID4(16 字节)为每个用户生成 ID。但是,我将该 ID 发送到前端,并且在前端已经使用了另一个 UUID。有一项服务总共不允许使用 32 个字节。我总共得到 32 个字节;来自前端的 16 个字节和来自后端的 16 个字节。所以,我正在考虑将每个用户的后端唯一 ID 修改为 8 个字节。
  • 为什么不在两个地方使用相同的 UUID?
  • 这适用于 UUID 固定的 GAT 服务器。它对于整个应用程序是静态的。不能从后端到前端使用。

标签: python random generator uuid


【解决方案1】:

好吧,您可以使用Linear Congruential Generator,通过正确选择参数,生成从 u64 到 u64 的完美映射。换句话说,如果您可以访问之前的 8 字节 UUID,您可以生成合理的随机下一个 8 字节 UUID,无需重复,直到整个 264 空间 ix 用完。它也可以在 O(log(N)) 中前后 N 步。

使用 NumPy、Python 3.7、Anaconda、Win 10 x64 的代码

#%%
import numpy as np

#%%
class LCG(object):

    UZERO: np.uint64 = np.uint64(0)
    UONE : np.uint64 = np.uint64(1)

    def __init__(self, seed: np.uint64, a: np.uint64, c: np.uint64) -> None:
        self._seed: np.uint64 = np.uint64(seed)
        self._a   : np.uint64 = np.uint64(a)
        self._c   : np.uint64 = np.uint64(c)

    def next(self) -> np.uint64:
        self._seed = self._a * self._seed + self._c
        return self._seed

    def seed(self) -> np.uint64:
        return self._seed

    def set_seed(self, seed: np.uint64) -> np.uint64:
        self._seed = seed

    def skip(self, ns: np.int64) -> None:
        """
        Signed argument - skip forward as well as backward

        The algorithm here to determine the parameters used to skip ahead is
        described in the paper F. Brown, "Random Number Generation with Arbitrary Stride,"
        Trans. Am. Nucl. Soc. (Nov. 1994). This algorithm is able to skip ahead in
        O(log2(N)) operations instead of O(N). It computes parameters
        A and C which can then be used to find x_N = A*x_0 + C mod 2^M.
        """

        nskip: np.uint64 = np.uint64(ns)

        a: np.uint64 = self._a
        c: np.uint64 = self._c

        a_next: np.uint64 = LCG.UONE
        c_next: np.uint64 = LCG.UZERO

        while nskip > LCG.UZERO:
            if (nskip & LCG.UONE) != LCG.UZERO:
                a_next = a_next * a
                c_next = c_next * a + c

            c = (a + LCG.UONE) * c
            a = a * a

            nskip = nskip >> LCG.UONE

        self._seed = a_next * self._seed + c_next


#%%
np.seterr(over='ignore')

a = np.uint64(6364136223846793005)
c = np.uint64(1)

seed = np.uint64(1)

rng64 = LCG(seed, a, c)

print(rng64.next())
print(rng64.next())
print(rng64.next())

#%%
rng64.skip(-3) # back by 3
print(rng64.next())
print(rng64.next())
print(rng64.next())

rng64.skip(-3) # back by 3
rng64.skip(2) # forward by 2
print(rng64.next())

【讨论】:

    【解决方案2】:

    在 Python 3.6 及更高版本中,这很容易:

    • 导入secrets模块:import secrets
    • 使用secrets.token_bytes(8) 生成随机字节序列。或者,如果该字符串应该是可读的,则使用以下生成 8 个字节的 16 个字符的字符串 (secrets.token_hex(8)),或 4 个字节的 8 个字符的字符串 (secrets.token_hex(4))。

    【讨论】:

    • 嗨,Peter,它在整个课程中是唯一的吗,例如,一个属于每个用户的唯一 ID,就像所有 20K 用户一样?
    • 一般来说,随机值本身不会是唯一的。您必须将随机数与其他唯一信息(例如数据库表的顺序分配的行号)配对。但是,如果您可以容忍重复 ID 的风险,请注意 20,000 个随机 8 字节值几乎肯定会彼此不同。有关唯一标识符,请参阅我的文章 more advice
    猜你喜欢
    • 1970-01-01
    • 2018-06-23
    • 2015-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-03
    相关资源
    最近更新 更多