python uuid1是顺序作为时间戳吗?

时间:2012-01-03 14:37:05

标签: python uuid

Python docs声明uuid1使用当前时间来形成uuid值。但我找不到确保UUID1顺序的引用。

>>> import uuid
>>> u1 = uuid.uuid1()
>>> u2 = uuid.uuid1()
>>> u1 < u2
True
>>> 

5 个答案:

答案 0 :(得分:15)

但并非总是如此:

>>> def test(n):
...     old = uuid.uuid1()
...     print old
...     for x in range(n):
...             new = uuid.uuid1()
...             if old >= new:
...                     print "OOops"
...                     break
...             old = new
...     print new
>>> test(1000000)
fd4ae687-3619-11e1-8801-c82a1450e52f
OOops
00000035-361a-11e1-bc9f-c82a1450e52f

答案 1 :(得分:9)

UUID不连续

不,标准UUID 意味着顺序。

显然,一些尝试是使用GUID(Microsoft在UUID上的扭曲)使它们顺序地帮助提高某些数据库场景中的性能。但顺序不是UUID的意图http://en.wikipedia.org/wiki/Globally_unique_identifier

MAC是最后的,不是第一个

不,在标准UUID中,MAC地址不是第一个组件。 MAC地址是版本1 UUID中的 last 组件。 http://en.wikipedia.org/wiki/Universally_unique_identifier

不要假设哪种类型的UUID

各种版本的UUID旨在相互兼容。因此,期望您始终拥有版本1 UUID可能是不合理的。其他程序员可能会使用其他版本。

规范

通过RFC 4122阅读UUID规范IETF。只有十几页。

答案 2 :(得分:5)

来自the python UUID docs

  

从主机ID,序列号和当前时间生成UUID。如果未给出node,则使用getnode()来获取硬件地址。如果给出clock_seq,则将其用作序列号;否则选择随机的14位序列号。

由此,我推断MAC地址是第一个,然后是(可能是随机的)序列号,然后是当前时间。因此,即使对于由同一台机器/进程生成的UUID,我也不希望保证这些单调增加。

答案 3 :(得分:4)

我在http://doanduyhai.wordpress.com/2012/07/05/apache-cassandra-tricks-and-traps/

中偶然发现了Cassandra / Python中可能的答案

Lexicographic TimeUUID order

Cassandra在所有原始类型中提供对类型1(基于时间和服务器)和类型4(随机)的UUID值的支持。

UUID(Unique Universal IDentifier)的主要用途是在潜在的分布式环境中获取真正唯一的标识符。

Cassandra确实支持版本1 UUID。它通过组合计算机的MAC地址和自公历开始以来100纳秒间隔的数量为您提供唯一标识符。

正如您所看到的,精度仅为100纳秒,但幸运的是它与时钟序列混合以增加随机性。此外,MAC地址也用于计算UUID,因此您不太可能在一台机器上遇到冲突,除非您需要处理非常大量的数据(不要忘记,不是每个人都是Twitter或Facebook)

UUID最重要的用例之一,特别是TimeUUID,是将其用作列密钥。由于Cassandra列键已排序,我们可以利用此功能为列族提供自然排序。

Hector客户端提供的默认com.eaio.uuid.UUID的问题在于它不易使用。作为ID,您可能需要将此值从服务器带到视图层,这就是问题所在。

基本上,com.eaio.uuid.UUID会覆盖toString()以提供UUID的String表示形式。但是,此字符串格式无法按字典顺序排序...

以下是连续生成的一些TimeUUID:

8e4cab00-c481-11e1-983b-20cf309ff6dc at some t1
2b6e3160-c482-11e1-addf-20cf309ff6dc at some t2 with t2 > t1

“2b6e3160-c482-11e1-addf-20cf309ff6dc”.compareTo(“8e4cab00-c481-11e1-983b-20cf309ff6dc”)给出-6意味着“2b6e3160-c482-11e1-addf-20cf309ff6dc”少于/之前“8e4cab00-c481-11e1-983b-20cf309ff6dc”< / strong>这是不正确的。

TimeUUID的当前文本显示按以下方式分割:

time_low – time_mid – time_high_and_version – variant_and_sequence – node

如果我们从time_high_and_version开始重新排序,我们可以按字典顺序对其进行排序:

time_high_and_version – time_mid – time_low – variant_and_sequence – node

实用程序类如下:

public static String reorderTimeUUId(String originalTimeUUID)
    {
        StringTokenizer tokens = new StringTokenizer(originalTimeUUID, "-");
        if (tokens.countTokens() == 5)
        {
            String time_low = tokens.nextToken();
            String time_mid = tokens.nextToken();
            String time_high_and_version = tokens.nextToken();
            String variant_and_sequence = tokens.nextToken();
            String node = tokens.nextToken();

            return time_high_and_version + '-' + time_mid + '-' + time_low + '-' + variant_and_sequence + '-' + node;

        }

        return originalTimeUUID;
    }

TimeUUID成为:

11e1-c481-8e4cab00-983b-20cf309ff6dc
11e1-c482-2b6e3160-addf-20cf309ff6dc

现在我们得到:

"11e1-c481-8e4cab00-983b-20cf309ff6dc".compareTo("11e1-c482-2b6e3160-addf-20cf309ff6dc") = -1

答案 4 :(得分:0)

无参数地使用uuid.uuid1()会产生非顺序的结果(see answer by @basil-bourque),但是如果您设置clock_seqnode的参数,则可以很容易地将其设为连续的(因为在此情况下案例uuid1使用python实现,该实现保证unique and sequential timestamp在当前进程中属于UUID的一部分):

import time

from uuid import uuid1, getnode
from random import getrandbits

_my_clock_seq = getrandbits(14)
_my_node = getnode()


def sequential_uuid(node=None):
    return uuid1(node=node, clock_seq=_my_clock_seq)


def alt_sequential_uuid(clock_seq=None):
    return uuid1(node=_my_node, clock_seq=clock_seq)



if __name__ == '__main__':
    from itertools import count
    old_n = uuid1()  # "Native"
    old_s = sequential_uuid()  # Sequential

    native_conflict_index = None

    t_0 = time.time()

    for x in count():
        new_n = uuid1()
        new_s = sequential_uuid()

        if old_n > new_n and not native_conflict_index:
            native_conflict_index = x

        if old_s >= new_s:
            print("OOops: non-sequential results for `sequential_uuid()`")
            break

        if (x >= 10*0x3fff and time.time() - t_0 > 30) or (native_conflict_index and x > 2*native_conflict_index):
            print('No issues for `sequential_uuid()`')
            break

        old_n = new_n
        old_s = new_s

    print(f'Conflicts for `uuid.uuid1()`: {bool(native_conflict_index)}')
    print(f"Tries: {x}")

多个流程问题

但是,如果您正在同一台计算机上运行一些并行进程,则:

  • node(默认为uuid.get_node())对于所有进程都是相同的;
  • clock_seq在某些过程中具有相同可能性的可能性很小(机会为1/16384)

那可能导致冲突!这是使用时的普遍关注    除非您可以从Python3.7中访问SafeUUID,否则uuid.uuid1可以在同一台计算机上并行处理。

如果您还确保为运行此代码的每个并行进程也将node设置为唯一值,那么就不会发生冲突。

即使您使用的是SafeUUID,并且设置了唯一的node,如果它们是在不同的进程中生成的,仍然可以具有非顺序ID。

如果可以接受一些与锁相关的开销,那么您可以将clock_seq存储在某些外部原子存储中(例如,存储在"locked"文件中),并在每次调用时对其进行递增:这允许具有相同的值在所有并行进程上用于node,并且还将使id-s顺序。对于所有并行流程都是使用multiprocessing创建的子流程的情况:可以使用multiprocessing.Value

来“共享” clock_seq